Commit ba876505 authored by Naoki Kambe's avatar Naoki Kambe

Merge branch 'master' into trac521

Conflicts:
	ChangeLog
	src/bin/bind10/bind10.py.in
	src/bin/bind10/bob.spec
	src/bin/bind10/tests/bind10_test.py.in
parents 4d505b0c 6c611b5c
......@@ -8,6 +8,90 @@
resending statistics data via bindctl manually.
(Trac #521, git tbdtbdtbdtbdtbdtbdtbdtbdtbdtbdtbdtbdtbd)
212. [bug] naokikambe
Fixed that the ModuleCCSession object may group_unsubscribe in the
closed CC session in being deleted.
(Trac #698, git 0355bddc92f6df66ef50b920edd6ec3b27920d61)
211. [func] shane
Implement "--brittle" option, which causes the server to exit
if any of BIND 10's processes dies.
(Trac #788, git 88c0d241fe05e5ea91b10f046f307177cc2f5bc5)
210. [bug] jerry
src/bin/auth: fixed a bug where type ANY queries don't provide
additional glue records for ANSWER section.
(Trac #699, git 510924ebc57def8085cc0e5413deda990b2abeee)
209. [func] jelte
Resolver now uses the NSAS when looking for a nameserver to
query for any specific zone. This also includes keeping track of
the RTT for that nameserver.
(Trac #495, git 76022a7e9f3ff339f0f9f10049aa85e5784d72c5)
208. [bug]* jelte
Resolver now answers REFUSED on queries that are not for class IN.
This includes the various CH TXT queries, which will be added
later.
(git 012f9e78dc611c72ea213f9bd6743172e1a2ca20)
207. [func] jelte
Resolver now starts listening on localhost:53 if no configuration
is set.
(Trac #471, git 1960b5becbba05570b9c7adf5129e64338659f07)
206. [func] shane
Add the ability to list the running BIND 10 processes using the
command channel. To try this, use "Boss show_processes".
(Trac #648, git 451bbb67c2b5d544db2f7deca4315165245d2b3b)
205. [bug] jinmei
b10-auth, src/lib/datasrc: fixed a bug where b10-auth could return
an empty additional section for delegation even if some glue is
crucial when it fails to find some other glue records in its data
source.
(Trac #646, git 6070acd1c5b2f7a61574eda4035b93b40aab3e2b)
204. [bug] jinmei
b10-auth, src/lib/datasrc: class ANY queries were not handled
correctly in the generic data source (mainly for sqlite3). It
could crash b10-auth in the worst case, and could result in
incorrect responses in some other cases.
(Trac #80, git c65637dd41c8d94399bd3e3cee965b694b633339)
203. [bug] zhang likun
Fix resolver cache memory leak: when cache is destructed, rrset
and message entries in it are not destructed properly.
(Trac #643, git aba4c4067da0dc63c97c6356dc3137651755ffce)
202. [func] vorner
It is possible to specify a different directory where we look for
configuration files (by -p) and different configuration file to
use (-c). Also, it is possible to specify the port on which
cmdctl should listen (--cmdctl-port).
(Trac #615, git 5514dd78f2d61a222f3069fc94723ca33fb3200b)
201. [bug] jerry
src/bin/bindctl: bindctl doesn't show traceback on shutdown.
(Trac #588, git 662e99ef050d98e86614c4443326568a0b5be437)
200. [bug] Jelte
Fixed a bug where incoming TCP connections were not closed.
(Trac #589, git 1d88daaa24e8b1ab27f28be876f40a144241e93b)
199. [func] ocean
Cache negative responses (NXDOMAIN/NODATA) from authoritative
server for recursive resolver.
(Trac #493, git f8fb852bc6aef292555063590c361f01cf29e5ca)
198. [bug] jinmei
b10-auth, src/lib/datasrc: fixed a bug where hot spot cache failed
to reuse cached SOA for negative responses. Due to this bug
b10-auth returned SERVFAIL when it was expected to return a
negative response immediately after a specific SOA query for
the zone.
(Trac #626, git 721a53160c15e8218f6798309befe940b9597ba0)
197. [bug] zhang likun
Remove expired message and rrset entries when looking up them
in cache, touch or remove the rrset entry in cache properly
......@@ -243,7 +327,7 @@ bind10-devel-20110224 released on February 24, 2011
timeout_client for sending an answer back to the client
timeout_lookup for stopping the resolving
(currently 2 and 3 have the same final effect)
(Trac 489, git 578ea7f4ba94dc0d8a3d39231dad2be118e125a2)
(Trac #489, git 578ea7f4ba94dc0d8a3d39231dad2be118e125a2)
159. [func] smann
The resolver now has a configurable set of root servers to start
......
To build "configure" file:
autoreconf
If using git (not the tarball), build the "configure" file:
autoreconf --install
To then build from source:
./configure
......
......@@ -15,9 +15,9 @@ five year plan are described here:
This release includes the bind10 master process, b10-msgq message
bus, b10-auth authoritative DNS server (with SQLite3 and in-memory
backends), b10-resolver forwarding DNS server, b10-cmdctl remote
control daemon, b10-cfgmgr configuration manager, b10-xfrin AXFR
inbound service, b10-xfrout outgoing AXFR service, b10-zonemgr
backends), b10-resolver recursive or forwarding DNS server, b10-cmdctl
remote control daemon, b10-cfgmgr configuration manager, b10-xfrin
AXFR inbound service, b10-xfrout outgoing AXFR service, b10-zonemgr
secondary manager, b10-stats statistics collection and reporting
daemon, and a new libdns++ library for C++ with a python wrapper.
......
......@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
AC_INIT(bind10-devel, 20110224, bind10-dev@isc.org)
AC_INIT(bind10-devel, 20110322, bind10-dev@isc.org)
AC_CONFIG_SRCDIR(README)
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h])
......@@ -663,6 +663,7 @@ AC_CONFIG_FILES([Makefile
src/lib/python/isc/net/tests/Makefile
src/lib/python/isc/notify/Makefile
src/lib/python/isc/notify/tests/Makefile
src/lib/python/isc/testutils/Makefile
src/lib/config/Makefile
src/lib/config/tests/Makefile
src/lib/config/tests/testdata/Makefile
......@@ -719,9 +720,8 @@ AC_OUTPUT([doc/version.ent
src/bin/stats/run_b10-stats_stub.sh
src/bin/stats/tests/stats_test
src/bin/bind10/bind10.py
src/bin/bind10/tests/bind10_test
src/bin/bind10/tests/bind10_test.py
src/bin/bind10/run_bind10.sh
src/bin/bind10/tests/bind10_test.py
src/bin/bindctl/run_bindctl.sh
src/bin/bindctl/bindctl_main.py
src/bin/bindctl/tests/bindctl_test
......
This diff is collapsed.
......@@ -1199,10 +1199,9 @@ TODO
<title>Incoming Zone Transfers</title>
<para>
The <command>b10-xfrin</command> process is started by
<command>bind10</command>.
It can be manually triggered to request an AXFR zone
transfer. When received, it is stored in the BIND 10
Incoming zones are transferred using the <command>b10-xfrin</command>
process which is started by <command>bind10</command>.
When received, the zone is stored in the BIND 10
data store, and its records can be served by
<command>b10-auth</command>.
In combination with <command>b10-zonemgr</command> (for
......@@ -1213,8 +1212,22 @@ TODO
<note><simpara>
The current development release of BIND 10 only supports
AXFR. (IXFR is not supported.)
<!-- TODO: sqlite3 data source only? -->
</simpara></note>
<!-- TODO:
how to tell bind10 you are a secondary?
when will it first attempt to check for new zone? (using REFRESH?)
what if zonemgr is not running?
what if a NOTIFY is sent?
-->
<para>
To manually trigger a zone transfer to retrieve a remote zone,
you may use the <command>bindctl</command> utility.
......@@ -1223,6 +1236,9 @@ TODO
<screen>&gt; <userinput>Xfrin retransfer zone_name="<option>foo.example.org</option>" master=<option>192.0.2.99</option></userinput></screen>
</para>
<!-- TODO: can that retransfer be used to identify a new zone? -->
<!-- TODO: what if doesn't exist at that master IP? -->
</chapter>
<chapter id="xfrout">
......@@ -1329,28 +1345,34 @@ what is XfroutClient xfr_client??
<!-- TODO: later the above will have some defaults -->
<para>
To enable forwarding, the upstream address and port must be
configured to forward queries to, such as:
<section>
<title>Forwarding</title>
<screen>
<para>
To enable forwarding, the upstream address and port must be
configured to forward queries to, such as:
<screen>
&gt; <userinput>config set Resolver/forward_addresses [{ "address": "<replaceable>192.168.1.1</replaceable>", "port": 53 }]</userinput>
&gt; <userinput>config commit</userinput>
</screen>
(Replace <replaceable>192.168.1.1</replaceable> to point to your
full resolver.)
</para>
(Replace <replaceable>192.168.1.1</replaceable> to point to your
full resolver.)
</para>
<para>
Normal iterative name service can be re-enabled by clearing the
forwarding address(es); for example:
<para>
Normal iterative name service can be re-enabled by clearing the
forwarding address(es); for example:
<screen>
<screen>
&gt; <userinput>config set Resolver/forward_addresses []</userinput>
&gt; <userinput>config commit</userinput>
</screen>
</para>
</para>
</section>
<!-- TODO: later try this
......
......@@ -207,7 +207,7 @@ public:
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data)
void cancel_ops(socket_type, per_descriptor_data& descriptor_data)
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
......
......@@ -205,7 +205,7 @@ public:
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data)
void cancel_ops(socket_type , per_descriptor_data& descriptor_data)
{
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
......
......@@ -40,7 +40,7 @@ class null_thread
public:
// Constructor.
template <typename Function>
null_thread(Function f)
null_thread(Function )
{
asio::system_error e(
asio::error::operation_not_supported, "thread");
......
......@@ -163,10 +163,6 @@ main(int argc, char* argv[]) {
my_command_handler);
cout << "[b10-auth] Configuration channel established." << endl;
if (uid != NULL) {
changeUser(uid);
}
xfrin_session = new Session(io_service.get_io_service());
cout << "[b10-auth] Xfrin session channel created." << endl;
xfrin_session->establish(NULL);
......@@ -190,6 +186,10 @@ main(int argc, char* argv[]) {
configureAuthServer(*auth_server, config_session->getFullConfig());
auth_server->updateConfig(ElementPtr());
if (uid != NULL) {
changeUser(uid);
}
cout << "[b10-auth] Server started." << endl;
io_service.run();
......
......@@ -210,6 +210,8 @@ Query::process() const {
// into answer section.
BOOST_FOREACH(RRsetPtr rrset, *target) {
response_.addRRset(Message::SECTION_ANSWER, rrset);
// Handle additional for answer section
getAdditional(*result.zone, *rrset.get());
}
} else {
response_.addRRset(Message::SECTION_ANSWER,
......
......@@ -341,12 +341,20 @@ TEST_F(QueryTest, apexAnyMatch) {
// in the answer section from the additional.
EXPECT_NO_THROW(Query(memory_datasrc, Name("example.com"),
RRType::ANY(), response).process());
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 0, 0,
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 0, 3,
"example.com. 3600 IN SOA . . 0 0 0 0 0\n"
"example.com. 3600 IN NS glue.delegation.example.com.\n"
"example.com. 3600 IN NS noglue.example.com.\n"
"example.com. 3600 IN NS example.net.\n",
NULL, NULL, mock_zone->getOrigin());
NULL, ns_addrs_txt, mock_zone->getOrigin());
}
TEST_F(QueryTest, mxANYMatch) {
EXPECT_NO_THROW(Query(memory_datasrc, Name("mx.example.com"),
RRType::ANY(), response).process());
responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
mx_txt, zone_ns_txt,
(string(ns_addrs_txt) + string(www_a_txt)).c_str());
}
TEST_F(QueryTest, glueANYMatch) {
......
......@@ -22,7 +22,7 @@
bind10 \- BIND 10 boss process
.SH "SYNOPSIS"
.HP \w'\fBbind10\fR\ 'u
\fBbind10\fR [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-verbose\fR]
\fBbind10\fR [\fB\-m\ \fR\fB\fIfile\fR\fR] [\fB\-n\fR] [\fB\-u\ \fR\fB\fIuser\fR\fR] [\fB\-v\fR] [\fB\-\-msgq\-socket\-file\ \fR\fB\fIfile\fR\fR] [\fB\-\-no\-cache\fR] [\fB\-\-user\ \fR\fB\fIuser\fR\fR] [\fB\-\-pretty\-name\ \fR\fB\fIname\fR\fR] [\fB\-\-brittle\fR] [\fB\-\-verbose\fR]
.SH "DESCRIPTION"
.PP
The
......@@ -66,6 +66,14 @@ or
\fBbind10\fR\&.
.RE
.PP
\fB\-\-brittle\fR
.RS 4
Shutdown if any of the child processes of
\fBbind10\fR
exit\&. This is intended to help developers debug the server, and should
not be used in production.
.RE
.PP
\fB\-v\fR, \fB\-\-verbose\fR
.RS 4
Display more about what is going on for
......
......@@ -139,7 +139,8 @@ class ProcessInfo:
self.restart_schedule = RestartSchedule()
self.uid = uid
self.username = username
self._spawn()
self.process = None
self.pid = None
def _preexec_work(self):
"""Function used before running a program that needs to run as a
......@@ -186,6 +187,11 @@ class ProcessInfo:
self.pid = self.process.pid
self.restart_schedule.set_run_start_time()
# spawn() and respawn() are the same for now, but in the future they
# may have different functionality
def spawn(self):
self._spawn()
def respawn(self):
self._spawn()
......@@ -194,14 +200,21 @@ class CChannelConnectError(Exception): pass
class BoB:
"""Boss of BIND class."""
def __init__(self, msgq_socket_file=None, nocache=False, verbose=False,
setuid=None, username=None):
def __init__(self, msgq_socket_file=None, data_path=None,
config_filename=None, nocache=False, verbose=False, setuid=None,
username=None, cmdctl_port=None, brittle=False):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
The msgq_socket_file specifies the UNIX domain socket file that the
msgq process listens on. If verbose is True, then the boss reports
what it is doing.
Data path and config filename are passed trough to config manager
(if provided) and specify the config file to be used.
The cmdctl_port is passed to cmdctl and specify on which port it
should listen.
"""
self.cc_session = None
self.ccs = None
......@@ -219,6 +232,10 @@ class BoB:
self.uid = setuid
self.username = username
self.verbose = verbose
self.data_path = data_path
self.config_filename = config_filename
self.cmdctl_port = cmdctl_port
self.brittle = brittle
def config_handler(self, new_config):
# If this is initial update, don't do anything now, leave it to startup
......@@ -270,6 +287,14 @@ class BoB:
answer = isc.config.ccsession.create_answer(0)
return answer
def get_processes(self):
pids = list(self.processes.keys())
pids.sort()
process_list = [ ]
for pid in pids:
process_list.append([pid, self.processes[pid].name])
return process_list
def command_handler(self, command, args):
if self.verbose:
sys.stdout.write("[bind10] Boss got command: " + str(command) + "\n")
......@@ -289,8 +314,13 @@ class BoB:
seq = self.cc_session.group_sendmsg(cmd, 'Stats')
self.cc_session.group_recvmsg(True, seq)
answer = isc.config.ccsession.create_answer(0)
elif command == "ping":
answer = isc.config.ccsession.create_answer(0, "pong")
elif command == "show_processes":
answer = isc.config.ccsession. \
create_answer(0, self.get_processes())
else:
answer = isc.config.ccsession.create_answer(1,
answer = isc.config.ccsession.create_answer(1,
"Unknown command")
return answer
......@@ -378,6 +408,7 @@ class BoB:
c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
True, not self.verbose, uid=self.uid,
username=self.username)
c_channel.spawn()
self.processes[c_channel.pid] = c_channel
self.log_started(c_channel.pid)
......@@ -399,9 +430,15 @@ class BoB:
Starts the configuration manager process
"""
self.log_starting("b10-cfgmgr")
bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
args = ["b10-cfgmgr"]
if self.data_path is not None:
args.append("--data-path=" + self.data_path)
if self.config_filename is not None:
args.append("--config-filename=" + self.config_filename)
bind_cfgd = ProcessInfo("b10-cfgmgr", args,
c_channel_env, uid=self.uid,
username=self.username)
bind_cfgd.spawn()
self.processes[bind_cfgd.pid] = bind_cfgd
self.log_started(bind_cfgd.pid)
......@@ -436,6 +473,7 @@ class BoB:
"""
self.log_starting(name, port, address)
newproc = ProcessInfo(name, args, c_channel_env)
newproc.spawn()
self.processes[newproc.pid] = newproc
self.log_started(newproc.pid)
......@@ -509,8 +547,13 @@ class BoB:
self.start_simple("b10-stats", c_channel_env)
def start_cmdctl(self, c_channel_env):
# XXX: we hardcode port 8080
self.start_simple("b10-cmdctl", c_channel_env, 8080)
"""
Starts the command control process
"""
args = ["b10-cmdctl"]
if self.cmdctl_port is not None:
args.append("--port=" + str(self.cmdctl_port))
self.start_process("b10-cmdctl", args, c_channel_env, self.cmdctl_port)
def start_all_processes(self):
"""
......@@ -677,20 +720,22 @@ class BoB:
if self.verbose:
sys.stdout.write("[bind10] All processes ended, server done.\n")
def _get_process_exit_status(self):
return os.waitpid(-1, os.WNOHANG)
def reap_children(self):
"""Check to see if any of our child processes have exited,
and note this for later handling.
"""
while True:
try:
(pid, exit_status) = os.waitpid(-1, os.WNOHANG)
(pid, exit_status) = self._get_process_exit_status()
except OSError as o:
if o.errno == errno.ECHILD: break
# XXX: should be impossible to get any other error here
raise
if pid == 0: break
if pid in self.processes:
# One of the processes we know about. Get information on it.
proc_info = self.processes.pop(pid)
proc_info.restart_schedule.set_run_stop_time()
......@@ -714,6 +759,11 @@ class BoB:
sys.stdout.write(
"[bind10] The b10-msgq process died, shutting down.\n")
self.runnable = False
# If we're in 'brittle' mode, we want to shutdown after
# any process dies.
if self.brittle:
self.runnable = False
else:
sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
......@@ -794,6 +844,52 @@ def process_rename(option, opt_str, value, parser):
"""Function that renames the process if it is requested by a option."""
isc.util.process.rename(value)
def parse_args(args=sys.argv[1:], Parser=OptionParser):
"""
Function for parsing command line arguments. Returns the
options object from OptionParser.
"""
parser = Parser(version=VERSION)
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("-n", "--no-cache", action="store_true", dest="nocache",
default=False, help="disable hot-spot cache in authoritative DNS server")
parser.add_option("-u", "--user", dest="user", type="string", default=None,
help="Change user after startup (must run as root)")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
help="display more about what is going on")
parser.add_option("--pretty-name", type="string", action="callback",
callback=process_rename,
help="Set the process name (displayed in ps, top, ...)")
parser.add_option("-c", "--config-file", action="store",
dest="config_file", default=None,
help="Configuration database filename")
parser.add_option("-p", "--data-path", dest="data_path",
help="Directory to search for configuration files",
default=None)
parser.add_option("--cmdctl-port", dest="cmdctl_port", type="int",
default=None, help="Port of command control")
parser.add_option("--pid-file", dest="pid_file", type="string",
default=None,
help="file to dump the PID of the BIND 10 process")
parser.add_option("--brittle", dest="brittle", action="store_true",
help="debugging flag: exit if any component dies")
(options, args) = parser.parse_args(args)
if options.cmdctl_port is not None:
try:
isc.net.parse.port_parse(options.cmdctl_port)
except ValueError as e:
parser.error(e)
if args:
parser.print_help()
sys.exit(1)
return options
def dump_pid(pid_file):
"""
Dump the PID of the current process to the specified file. If the given
......@@ -823,33 +919,14 @@ def unlink_pid_file(pid_file):
if error.errno is not errno.ENOENT:
raise
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("-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("-n", "--no-cache", action="store_true", dest="nocache",
default=False, help="disable hot-spot cache in authoritative DNS server")
parser.add_option("-u", "--user", dest="user", type="string", default=None,
help="Change user after startup (must run as root)")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
help="display more about what is going on")
parser.add_option("--pretty-name", type="string", action="callback",
callback=process_rename,
help="Set the process name (displayed in ps, top, ...)")
parser.add_option("--pid-file", dest="pid_file", type="string",