Commit 6fe86386 authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'master' into trac2503

parents 3de3abb8 cbb1e342
522. [func]* jelte
Configuration of TSIG keys for b10-xfrin has changed; instead of
specifying the full TSIG key (<name>:<base64>:<algo>) it now expects
just the name, and uses the global TSIG Key Ring like all the other
components (configuration list /tsig_keys/keys).
Note: this is not automatically updated, so if you use TSIG in
xfrin, you need to update your configuration.
(Trac #1351, git e65b7b36f60f14b7abe083da411e6934cdfbae7a)
521. [func] marcin
Implemented definitions for DHCPv6 standard options identified
by codes up to 48. These definitions are now used by the DHCPv6
server to create instances of options being sent to a client.
(Trac #2491, git 0a4faa07777189ed9c25211987a1a9b574015a95)
520. [func] jelte
The system no longer prints initial log messages to stdout
regardless of what logging configuration is present, but it
temporarily stores any log messages until the configuration is
processed. If there is no specific configuration, or if the
configuration cannot be accessed, it will still fall back to stdout.
Note that there are still a few instances where output is printed,
these shall be addressed separately.
Note also that, currently, in case it falls back to stdout (such as
when it cannot connect to b10-cfgmgr), all log messages are always
printed (including debug messages), regardless of whether -v was
used. This shall also be addressed in a future change.
(Trac #2445, git 74a0abe5a6d10b28e4a3e360e87b129c232dea68)
519. [bug] muks
Fixed a problem in inmem NSEC lookup which caused returning an
incorrect NSEC record or (in rare cases) assert failures
when a non-existent domain was queried, which was a sub-domain of
a domain that existed.
(Trac #2504, git 835553eb309d100b062051f7ef18422d2e8e3ae4)
518. [func] stephen
Extend DHCP MySQL backend to handle IPv4 addresses.
(Trac #2404, git ce7db48d3ff5d5aad12b1da5e67ae60073cb2607)
517. [func] stephen
Added IOAddress::toBytes() to get byte representation of address.
Also added convenience methods for V4/V6 address determination.
(Trac #2396, git c23f87e8ac3ea781b38d688f8f7b58539f85e35a)
516. [bug] marcin
Fixed 'make distcheck' failure when running perfdhcp unit tests.
The unit tests used to read files from the folder specified
with the path relative to current folder, thus when the test was
run from a different folder the files could not be found.
(Trac #2479, git 4e8325e1b309f1d388a3055ec1e1df98c377f383)
515. [bug] jinmei
The in-memory data source now accepts an RRSIG provided without
a covered RRset in loading. A subsequent query for its owner name
......@@ -903,11 +903,12 @@ AC_SUBST(MULTITHREADING_FLAG)
# TODO: set DISTCHECK_GTEST_CONFIGURE_FLAG for --with-gtest too
if test "x$enable_gtest" = "xyes" ; then
if test -n "$with_gtest_source" ; then
if test "x$GTEST_SOURCE" = "xyes" ; then
......@@ -1375,6 +1376,7 @@ AC_OUTPUT([doc/version.ent
......@@ -580,8 +580,8 @@ INPUT = ../src/lib/exceptions ../src/lib/cc \
../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
../src/bin/sockcreator/ ../src/lib/util/ ../src/lib/util/io/ \
../src/lib/util/threads/ ../src/lib/resolve ../src/lib/acl \
../src/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/bin/dhcp4 \
../tests/tools/perfdhcp devel
../src/lib/statistics ../src/bin/dhcp6 ../src/lib/dhcp ../src/lib/dhcpsrv \
../src/bin/dhcp4 ../tests/tools/perfdhcp devel
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......@@ -472,7 +472,7 @@ var/
Some operating systems or softare package vendors may
Some operating systems or software package vendors may
provide ready-to-use, pre-built software packages for
the BIND 10 suite.
Installing a pre-built package means you do not need to
......@@ -1841,10 +1841,8 @@ config set /Boss/components/b10-zonemgr/kind dispensable
The key ring lives in the configuration in "tsig_keys/keys". Most of
the system uses the keys from there &mdash; ACLs, authoritative server to
sign responses to signed queries, and <command>b10-xfrout</command>
to sign transfers. The <command>b10-xfrin</command> uses its own
configuration for keys, but that will be fixed in Trac ticket
<ulink url="">#1351</ulink>.
sign responses to signed queries, and <command>b10-xfrin</command>
and <command>b10-xfrout</command> to sign transfers.
......@@ -2157,7 +2155,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
you indicate that the system is not usable without the
component and if such component fails, the system shuts
down no matter when the failure happened. This is the
behaviour of the core components (the ones you can't turn
behavior of the core components (the ones you can't turn
off), but you can declare any other components as core as
well if you wish (but you can turn these off, they just
can't fail).
......@@ -2721,6 +2719,15 @@ TODO
If you want to use TSIG for incoming transfers, a system wide TSIG
key ring must be configured (see <xref linkend="tsig-key-ring"/>).
To specify a key to use, set tsig_key value to the name of the key
to use from the key ring.
&gt; <userinput>config set Xfrin/zones[0]/tsig_key "<option>example.key</option>"</userinput>
<title>Enabling IXFR</title>
......@@ -147,7 +147,7 @@ main(int argc, char* argv[]) {
// Initialize logging. If verbose, we'll use maximum verbosity.
(verbose ? isc::log::DEBUG : isc::log::INFO),
isc::log::MAX_DEBUG_LEVEL, NULL, true);
int ret = 0;
......@@ -256,7 +256,9 @@ main(int argc, char* argv[]) {
// If we haven't registered callback for data sources, this will be just
// no-op.
if (config_session != NULL) {
delete xfrin_session;
delete config_session;
......@@ -225,7 +225,7 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
RRsetPtr rrset_version = RRsetPtr(new RRset(version_name, RRClass::CH(),
RRType::TXT(), RRTTL(0)));
rrset_version->addRdata(generic::TXT("\"" PACKAGE_STRING "\""));
message.addRRset(Message::SECTION_ANSWER, rrset_version);
RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
......@@ -76,7 +76,7 @@ import isc.bind10.socket_cache
import libutil_io_python
import tempfile
isc.log.init("b10-boss", buffer=True)
logger = isc.log.Logger("boss")
# Pending system-wide debug level definitions, the ones we
......@@ -216,6 +216,12 @@ class BoB:
self.clear_config = clear_config
self.cmdctl_port = cmdctl_port
self.wait_time = wait_time
self.msgq_timeout = 5
# _run_under_unittests is only meant to be used when testing. It
# bypasses execution of some code to help with testing.
self._run_under_unittests = False
self._component_configurator = isc.bind10.component.Configurator(self,
# The priorities here make them start in the correct order. First
......@@ -332,6 +338,7 @@ class BoB:
self.components = {}
def _read_bind10_config(self):
......@@ -408,12 +415,21 @@ class BoB:
# raised which is caught by the caller of start_all_processes(); this kills
# processes started up to that point before terminating the program.
def _make_process_info(self, name, args, env,
dev_null_stdout=False, dev_null_stderr=False):
Wrapper around ProcessInfo(), useful to override
ProcessInfo() creation during testing.
return ProcessInfo(name, args, env, dev_null_stdout, dev_null_stderr)
def start_msgq(self):
Start the message queue and connect to the command channel.
msgq_proc = ProcessInfo("b10-msgq", ["b10-msgq"], self.c_channel_env,
msgq_proc = self._make_process_info("b10-msgq", ["b10-msgq"],
True, not self.verbose)
......@@ -421,8 +437,12 @@ class BoB:
# Now connect to the c-channel
cc_connect_start = time.time()
while self.cc_session is None:
# if we are run under unittests, break
if self._run_under_unittests:
# if we have been trying for "a while" give up
if (time.time() - cc_connect_start) > 5:
if (time.time() - cc_connect_start) > self.msgq_timeout:
raise CChannelConnectError("Unable to connect to c-channel after 5 seconds")
......@@ -434,6 +454,7 @@ class BoB:
# Subscribe to the message queue. The only messages we expect to receive
# on this channel are once relating to process startup.
if self.cc_session is not None:
return msgq_proc
......@@ -450,13 +471,14 @@ class BoB:
args.append("--config-filename=" + self.config_filename)
if self.clear_config:
bind_cfgd = ProcessInfo("b10-cfgmgr", args,
bind_cfgd = self._make_process_info("b10-cfgmgr", args,
# Wait for the configuration manager to start up as subsequent initialization
# cannot proceed without it. The time to wait can be set on the command line.
# Wait for the configuration manager to start up as
# subsequent initialization cannot proceed without it. The
# time to wait can be set on the command line.
time_remaining = self.wait_time
msg, env = self.cc_session.group_recvmsg()
while time_remaining > 0 and not self.process_running(msg, "ConfigManager"):
......@@ -499,7 +521,7 @@ class BoB:
The port and address arguments are for log messages only.
self.log_starting(name, port, address)
newproc = ProcessInfo(name, args, c_channel_env)
newproc = self._make_process_info(name, args, c_channel_env)
return newproc
......@@ -611,7 +633,6 @@ class BoB:
if self.msgq_socket_file is not None:
c_channel_env["BIND10_MSGQ_SOCKET_FILE"] = self.msgq_socket_file
# try to connect, and if we can't wait a short while
self.cc_session =
......@@ -735,10 +756,12 @@ class BoB:
(pid, exit_status) = self._get_process_exit_status()
except OSError as o:
if o.errno == errno.ECHILD: break
if o.errno == errno.ECHILD:
# XXX: should be impossible to get any other error here
if pid == 0: break
if pid == 0:
if pid in self.components:
# One of the components we know about. Get information on it.
component = self.components.pop(pid)
......@@ -909,7 +932,9 @@ class BoB:
if self._srv_socket is not None:
if os.path.exists(self._socket_path):
if os.path.isdir(self._tmpdir):
def _srv_accept(self):
This diff is collapsed.
......@@ -27,7 +27,7 @@ import glob
import os.path
import imp
import isc.log
isc.log.init("b10-cfgmgr", buffer=True)
from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError, logger
from isc.log_messages.cfgmgr_messages import *
......@@ -49,7 +49,7 @@ from hashlib import sha1
from isc.util import socketserver_mixin
from isc.log_messages.cmdctl_messages import *
isc.log.init("b10-cmdctl", buffer=True)
logger = isc.log.Logger("cmdctl")
# Debug level for communication with BIND10
......@@ -45,7 +45,7 @@ import os.path
import signal
import socket
isc.log.init("b10-ddns", buffer=True)
logger = isc.log.Logger("ddns")
......@@ -17,6 +17,7 @@
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <log/logger_support.h>
#include <log/logger_manager.h>
#include <boost/lexical_cast.hpp>
......@@ -93,9 +94,10 @@ main(int argc, char* argv[]) {
// Initialize logging. If verbose, we'll use maximum verbosity.
// If standalone is enabled, do not buffer initial log messages
(verbose_mode ? isc::log::DEBUG : isc::log::INFO),
isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
LOG_INFO(dhcp4_logger, DHCP4_STARTING);
.arg(getpid()).arg(port_number).arg(verbose_mode ? "yes" : "no")
......@@ -112,6 +114,10 @@ main(int argc, char* argv[]) {
LOG_ERROR(dhcp4_logger, DHCP4_SESSION_FAIL).arg(ex.what());
// Let's continue. It is useful to have the ability to run
// DHCP server in stand-alone mode, e.g. for testing
// We do need to make sure logging is no longer buffered
// since then it would not print until dhcp6 is stopped
isc::log::LoggerManager log_manager;
} else {
......@@ -24,6 +24,7 @@
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/pkt6.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/dhcp6_srv.h>
......@@ -348,13 +349,29 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
// @todo: Implement Option6_StatusCode and rewrite this code here
vector<uint8_t> data(text.c_str(), text.c_str() + text.length());
data.insert(data.begin(), static_cast<uint8_t>(code % 256));
data.insert(data.begin(), static_cast<uint8_t>(code >> 8));
OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data));
return (status);
// @todo This function uses OptionCustom class to manage contents
// of the data fields. Since this this option is frequently used
// it may be good to implement dedicated class to avoid performance
// impact.
// Get the definition of the option holding status code.
OptionDefinitionPtr status_code_def =
LibDHCP::getOptionDef(Option::V6, D6O_STATUS_CODE);
// This definition is assumed to be initialized in LibDHCP.
// As there is no dedicated class to represent Status Code
// the OptionCustom class should be returned here.
boost::shared_ptr<OptionCustom> option_status =
OptionCustom>(status_code_def->optionFactory(Option::V6, D6O_STATUS_CODE));
// Set status code to 'code' (0 - means data field #0).
option_status->writeInteger(code, 0);
// Set a message (1 - means data field #1).
option_status->writeString(text, 1);
return (option_status);
Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
......@@ -430,6 +447,10 @@ OptionPtr Dhcpv6Srv::handleIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
// but different wording below)
if (!subnet) {
// Create empty IA_NA option with IAID matching the request.
// Note that we don't use OptionDefinition class to create this option.
// This is because we prefer using a constructor of Option6IA that
// initializes IAID. Otherwise we would have to use setIAID() after
// creation of the option which has some performance implications.
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
// Insert status code NoAddrsAvail.
......@@ -471,6 +492,8 @@ OptionPtr Dhcpv6Srv::handleIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
hint, fake_allocation);
// Create IA_NA that we will put in the response.
// Do not use OptionDefinition to create option's instance so
// as we can initialize IAID using a constructor.
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
if (lease) {
......@@ -17,6 +17,7 @@
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <log/logger_support.h>
#include <log/logger_manager.h>
#include <boost/lexical_cast.hpp>
......@@ -103,9 +104,10 @@ main(int argc, char* argv[]) {
// Initialize logging. If verbose, we'll use maximum verbosity.
// If standalone is enabled, do not buffer initial log messages
(verbose_mode ? isc::log::DEBUG : isc::log::INFO),
isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
LOG_INFO(dhcp6_logger, DHCP6_STARTING);
.arg(getpid()).arg(port_number).arg(verbose_mode ? "yes" : "no")
......@@ -121,6 +123,10 @@ main(int argc, char* argv[]) {
LOG_ERROR(dhcp6_logger, DHCP6_SESSION_FAIL).arg(ex.what());
// Let's continue. It is useful to have the ability to run
// DHCP server in stand-alone mode, e.g. for testing
// We do need to make sure logging is no longer buffered
// since then it would not print until dhcp6 is stopped
isc::log::LoggerManager log_manager;
} else {
......@@ -801,12 +801,23 @@ TEST_F(Dhcpv6SrvTest, StatusCode) {
ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
// a dummy content for client-id
uint8_t expected[] = {0x0, 0x3, 0x41, 0x42, 0x43, 0x44, 0x45};
OptionBuffer exp(expected, expected + sizeof(expected));
uint8_t expected[] = {
0x0, 0xD, // option code = 14
0x0, 0x7, // option length = 7
0x0, 0x3, // status code = 3
0x41, 0x42, 0x43, 0x44, 0x45 // string value ABCDE
// Create the option.
OptionPtr status = srv->createStatusCode(3, "ABCDE");
EXPECT_TRUE(status->getData() == exp);
// Allocate an output buffer. We will store the option
// in wire format here.
OutputBuffer buf(sizeof(expected));
// Prepare the wire format.
// Check that the option buffer has valid length (option header + data).
ASSERT_EQ(sizeof(expected), buf.getLength());
// Verify the contents of the option.
EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
// This test verifies if the selectSubnet() method works as expected.
......@@ -143,7 +143,7 @@ main(int argc, char* argv[]) {
// temporary initLogger() code. If verbose, we'll use maximum verbosity.
(verbose ? isc::log::DEBUG : isc::log::INFO),
isc::log::MAX_DEBUG_LEVEL, NULL, true);
// Print the starting message
string cmdline = argv[0];
......@@ -31,7 +31,7 @@ import isc.util.process
import isc.log
from isc.log_messages.stats_messages import *
isc.log.init("b10-stats", buffer=True)
logger = isc.log.Logger("stats")
# Some constants for debug levels.
......@@ -682,7 +682,7 @@ if __name__ == "__main__":
help="enable maximum debug logging")
(options, args) = parser.parse_args()
if options.verbose:
isc.log.init("b10-stats", "DEBUG", 99)
isc.log.init("b10-stats", "DEBUG", 99, buffer=True)
stats = Stats()
except OptionValueError as ove:
......@@ -39,7 +39,7 @@ import isc.util.process
import isc.log
from isc.log_messages.stats_httpd_messages import *
isc.log.init("b10-stats-httpd", buffer=True)
logger = isc.log.Logger("stats-httpd")
# Some constants for debug levels.
......@@ -609,7 +609,7 @@ if __name__ == "__main__":
help="enable maximum debug logging")
(options, args) = parser.parse_args()
if options.verbose:
isc.log.init("b10-stats-httpd", "DEBUG", 99)
isc.log.init("b10-stats-httpd", "DEBUG", 99, buffer=True)
stats_httpd = StatsHttpd()
except OptionValueError as ove:
......@@ -112,20 +112,18 @@ in separate zonemgr process.
<varname>master_addr</varname> (the zone master to transfer from),
<varname>master_port</varname> (defaults to 53),
<varname>use_ixfr</varname> (defaults to false), and
<varname>tsig_key</varname> (optional TSIG key to use).
The <varname>tsig_key</varname> is specified using a full string
colon-delimited name:key:algorithm representation (e.g.
<varname>tsig_key</varname> (optional TSIG key name to use).
The <varname>tsig_key</varname> is specified using a name that
corresponds to one of the TSIG keys configured in the global
TSIG key ring (<quote>/tsig_keys/keys</quote>).
<!-- TODO: document this better -->
<!-- TODO: the tsig_key format may change -->
(The site-wide <varname>master_addr</varname> and
<varname>master_port</varname> configurations are deprecated;
use the <varname>zones</varname> list configuration instead.)
<!-- NOTE: also tsig_key but not mentioning since so short lived. -->
<!-- TODO: formating -->
......@@ -26,6 +26,7 @@ from xfrin import *
import xfrin
from isc.xfrin.diff import Diff
import isc.log
from isc.server_common.tsig_keyring import init_keyring, get_keyring
# If we use any python library that is basically a wrapper for
# a library we use as well (like sqlite3 in our datasources),
# we must make sure we import ours first; If we have special
......@@ -139,6 +140,16 @@ class MockCC(MockModuleCCSession):
if identifier == "zones/use_ixfr":
return False
def add_remote_config_by_name(self, name, callback):
def get_remote_config_value(self, module, identifier):
if module == 'tsig_keys' and identifier == 'keys':
return ([''], True)
raise Exception('MockCC requested for unknown config value ' +
+ module + "/" + identifier)
def remove_remote_config(self, module_name):
......@@ -229,6 +240,7 @@ class MockXfrin(Xfrin):
def _cc_setup(self):
self._tsig_key = None
self._module_cc = MockCC()
def _get_db_file(self):
......@@ -2427,9 +2439,10 @@ class TestXfrin(unittest.TestCase):
self.assertEqual(str(zone_info.master_addr), zone_config['master_addr'])
self.assertEqual(zone_info.master_port, zone_config['master_port'])
if 'tsig_key' in zone_config:
self.assertEqual(zone_info.tsig_key.to_text(), TSIGKey(zone_config['tsig_key']).to_text())
if 'use_ixfr' in zone_config and\
......@@ -2562,7 +2575,7 @@ class TestXfrin(unittest.TestCase):
{ 'name': 'test2.example.',
'master_addr': '',
'master_port': 53,
'tsig_key': 'badkey'
'tsig_key': 'badkey..'
self.assertEqual(self.xfr.config_handler(zones)['result'][0], 1)
......@@ -2581,13 +2594,14 @@ class TestXfrin(unittest.TestCase):
self.assertEqual(self.xfr.config_handler(config)['result'][0], 0)
def common_ixfr_setup(self, xfr_mode, use_ixfr):
def common_ixfr_setup(self, xfr_mode, use_ixfr, tsig_key_str = None):
# This helper method explicitly sets up a zone configuration with
# use_ixfr, and invokes either retransfer or refresh.
# Shared by some of the following test cases.
config = {'zones': [
{'name': '',
'master_addr': '',
'tsig_key': tsig_key_str,
'use_ixfr': use_ixfr}]}
self.assertEqual(self.xfr.config_handler(config)['result'][0], 0)
......@@ -2603,6 +2617,34 @@ class TestXfrin(unittest.TestCase):
self.common_ixfr_setup('refresh', True)
self.assertEqual(RRType.IXFR(), self.xfr.xfrin_started_request_type)
def test_command_handler_retransfer_with_tsig(self):
self.common_ixfr_setup('retransfer', False, '')