Commit f06ce638 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge branches 'work/ports/auth' and 'work/ports/boss'

......@@ -681,6 +681,8 @@ AC_CONFIG_FILES([Makefile
src/lib/nsas/tests/Makefile
src/lib/cache/Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
])
AC_OUTPUT([doc/version.ent
src/bin/cfgmgr/b10-cfgmgr.py
......
......@@ -568,7 +568,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/
# 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
......
......@@ -52,6 +52,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_auth_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
b10_auth_LDADD += $(SQLITE_LIBS)
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
......
......@@ -56,6 +56,41 @@
"item_type": "integer",
"item_optional": true,
"item_default": 60
},
{
"item_name": "listen_on",
"item_type": "list",
"item_optional": false,
"item_default": [
{
"address": "::1",
"port": 5300
},
{
"address": "127.0.0.1",
"port": 5300
}
],
"list_item_spec": {
"item_name": "address",
"item_type": "map",
"item_optional": false,
"item_default": {},
"map_item_spec": [
{
"item_name": "address",
"item_type": "string",
"item_optional": false,
"item_default": "::1"
},
{
"item_name": "port",
"item_type": "integer",
"item_optional": false,
"item_default": 5300
}
]
}
}
],
"commands": [
......
......@@ -69,6 +69,7 @@ using namespace isc::data;
using namespace isc::config;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::server_common::portconfig;
class AuthSrvImpl {
private:
......@@ -109,6 +110,9 @@ public:
/// Query counters for statistics
AuthCounters counters_;
/// Addresses we listen on
AddressList listen_addresses_;
private:
std::string db_file_;
......@@ -750,3 +754,18 @@ uint64_t
AuthSrv::getCounter(const AuthCounters::CounterType type) const {
return (impl_->counters_.getCounter(type));
}
const AddressList&
AuthSrv::getListenAddresses() const {
return (impl_->listen_addresses_);
}
void
AuthSrv::setListenAddresses(const AddressList& addresses) {
installListenAddresses(addresses, impl_->listen_addresses_, *dnss_);
}
void
AuthSrv::setDNSService(asiolink::DNSService& dnss) {
dnss_ = &dnss;
}
......@@ -25,6 +25,7 @@
#include <config/ccsession.h>
#include <asiolink/asiolink.h>
#include <server_common/portconfig.h>
#include <auth/statistics.h>
namespace isc {
......@@ -353,11 +354,24 @@ public:
/// \return the value of the counter.
uint64_t getCounter(const AuthCounters::CounterType type) const;
/**
* \brief Set and get the addresses we listen on.
*/
void setListenAddresses(const isc::server_common::portconfig::AddressList&
addreses);
const isc::server_common::portconfig::AddressList& getListenAddresses()
const;
/// \brief Assign an ASIO DNS Service queue to this Auth object
void setDNSService(asiolink::DNSService& dnss);
private:
AuthSrvImpl* impl_;
asiolink::SimpleCallback* checkin_;
asiolink::DNSLookup* dns_lookup_;
asiolink::DNSAnswer* dns_answer_;
asiolink::DNSService* dnss_;
};
#endif // __AUTH_SRV_H
......
......@@ -44,11 +44,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>b10-auth</command>
<arg><option>-4</option></arg>
<arg><option>-6</option></arg>
<arg><option>-a <replaceable>address</replaceable></option></arg>
<arg><option>-n</option></arg>
<arg><option>-p <replaceable>number</replaceable></option></arg>
<arg><option>-u <replaceable>username</replaceable></option></arg>
<arg><option>-v</option></arg>
</cmdsynopsis>
......@@ -84,39 +80,6 @@
<para>The arguments are as follows:</para>
<variablelist>
<varlistentry>
<term><option>-4</option></term>
<listitem><para>
Enables IPv4 only mode.
This switch may not be used with <option>-6</option> nor
<option>-a</option>.
By default, it listens on both IPv4 and IPv6 (if capable).
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-6</option></term>
<listitem><para>
Enables IPv6 only mode.
This switch may not be used with <option>-4</option> nor
<option>-a</option>.
By default, it listens on both IPv4 and IPv6 (if capable).
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-a <replaceable>address</replaceable></option></term>
<listitem>
<para>The IPv4 or IPv6 address to listen on.
This switch may not be used with <option>-4</option> nor
<option>-6</option>.
The default is to listen on all addresses.
(This is a short term workaround. This argument may change.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
<listitem><para>
......@@ -129,16 +92,6 @@
<!-- TODO: this is SQLite3 only -->
</varlistentry>
<varlistentry>
<term><option>-p <replaceable>number</replaceable></option></term>
<listitem><para>
The port number it listens on.
The default is 5300.</para>
<note><simpara>This prototype runs on all interfaces
and on this nonstandard port.</simpara></note>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-u <replaceable>username</replaceable></option></term>
<listitem>
......
......@@ -23,4 +23,5 @@ query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la
query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
query_bench_LDADD += $(SQLITE_LIBS)
......@@ -32,11 +32,14 @@
#include <auth/config.h>
#include <auth/common.h>
#include <server_common/portconfig.h>
using namespace std;
using boost::shared_ptr;
using namespace isc::dns;
using namespace isc::data;
using namespace isc::datasrc;
using namespace isc::server_common::portconfig;
namespace {
// Forward declaration
......@@ -210,6 +213,60 @@ public:
}
};
/**
* \brief Configuration parser for listen_on.
*
* It parses and sets the listening addresses of the server.
*
* It acts in unusual way. Since actually binding (changing) the sockets
* is an operation that is expected to throw often, it shouldn't happen
* in commit. Thefere we do it in build. But if the config is not committed
* then, we would have it wrong. So we store the old addresses and if
* commit is not called before destruction of the object, we return the
* old addresses (which is the same kind of dangerous operation, but it is
* expected that if we just managed to bind some and had the old ones binded
* before, it should work).
*
* We might do something better in future (like open only the ports that are
* extra, put them in in commit and close the old ones), but that's left out
* for now.
*/
class ListenAddressConfig : public AuthConfigParser {
public:
ListenAddressConfig(AuthSrv& server) :
server_(server)
{ }
~ ListenAddressConfig() {
if (rollbackAddresses_.get() != NULL) {
server_.setListenAddresses(*rollbackAddresses_);
}
}
private:
typedef auto_ptr<AddressList> AddrListPtr;
public:
virtual void build(ConstElementPtr config) {
AddressList newAddresses = parseAddresses(config, "listen_on");
AddrListPtr old(new AddressList(server_.getListenAddresses()));
server_.setListenAddresses(newAddresses);
/*
* Set the rollback addresses only after successful setting of the
* new addresses, so we don't try to rollback if the setup is
* unsuccessful (the above can easily throw).
*/
rollbackAddresses_ = old;
}
virtual void commit() {
rollbackAddresses_.release();
}
private:
AuthSrv& server_;
/**
* This is the old address list, if we expect to roll back. When we commit,
* this is set to NULL.
*/
AddrListPtr rollbackAddresses_;
};
// This is a generalized version of create function that can create
// an AuthConfigParser object for "internal" use.
AuthConfigParser*
......@@ -226,6 +283,8 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id,
return (new StatisticsIntervalConfig(server));
} else if (internal && config_id == "datasources/memory") {
return (new MemoryDatasourceConfig(server));
} else if (config_id == "listen_on") {
return (new ListenAddressConfig(server));
} else if (config_id == "_commit_throw") {
// This is for testing purpose only and should not appear in the
// actual configuration syntax. While this could crash the caller
......
......@@ -42,6 +42,7 @@
#include <auth/change_user.h>
#include <auth/auth_srv.h>
#include <asiolink/asiolink.h>
#include <log/dummylog.h>
using namespace std;
using namespace isc::data;
......@@ -55,9 +56,6 @@ namespace {
bool verbose_mode = false;
// Default port current 5300 for testing purposes
const char* DNSPORT = "5300";
/* need global var for config/command handlers.
* todo: turn this around, and put handlers in the authserver
* class itself? */
......@@ -76,13 +74,8 @@ my_command_handler(const string& command, ConstElementPtr args) {
void
usage() {
cerr << "Usage: b10-auth [-a address] [-p port] [-u user] [-4|-6] [-nv]"
<< endl;
cerr << "\t-a: specify the address to listen on (default: all) " << endl;
cerr << "\t-p: specify the port to listen on (default: " << DNSPORT << ")"
cerr << "Usage: b10-auth [-u user] [-nv]"
<< endl;
cerr << "\t-4: listen on all IPv4 addresses (incompatible with -a)" << endl;
cerr << "\t-6: listen on all IPv6 addresses (incompatible with -a)" << endl;
cerr << "\t-n: do not cache answers in memory" << endl;
cerr << "\t-u: change process UID to the specified user" << endl;
cerr << "\t-v: verbose output" << endl;
......@@ -93,38 +86,20 @@ usage() {
int
main(int argc, char* argv[]) {
int ch;
const char* port = DNSPORT;
const char* address = NULL;
const char* uid = NULL;
bool use_ipv4 = true, use_ipv6 = true, cache = true;
bool cache = true;
while ((ch = getopt(argc, argv, "46a:np:u:v")) != -1) {
while ((ch = getopt(argc, argv, ":nu:v")) != -1) {
switch (ch) {
case '4':
// Note that -4 means "ipv4 only", we need to set "use_ipv6" here,
// not "use_ipv4". We could use something like "ipv4_only", but
// we found the negatively named variable could confuse the code
// logic.
use_ipv6 = false;
break;
case '6':
// The same note as -4 applies.
use_ipv4 = false;
break;
case 'n':
cache = false;
break;
case 'a':
address = optarg;
break;
case 'p':
port = optarg;
break;
case 'u':
uid = optarg;
break;
case 'v':
verbose_mode = true;
isc::log::denabled = true;
break;
case '?':
default:
......@@ -136,18 +111,6 @@ main(int argc, char* argv[]) {
usage();
}
if (!use_ipv4 && !use_ipv6) {
cerr << "[b10-auth] Error: Cannot specify both -4 and -6 "
<< "at the same time" << endl;
usage();
}
if ((!use_ipv4 || !use_ipv6) && address != NULL) {
cerr << "[b10-auth] Error: Cannot specify -4 or -6 "
<< "at the same time as -a" << endl;
usage();
}
int ret = 0;
// XXX: we should eventually pass io_service here.
......@@ -182,21 +145,8 @@ main(int argc, char* argv[]) {
DNSLookup* lookup = auth_server->getDNSLookupProvider();
DNSAnswer* answer = auth_server->getDNSAnswerProvider();
DNSService* dns_service;
if (address != NULL) {
// XXX: we can only specify at most one explicit address.
// This also means the server cannot run in the dual address
// family mode if explicit addresses need to be specified.
// We don't bother to fix this problem, however. The -a option
// is a short term workaround until we support dynamic listening
// port allocation.
dns_service = new DNSService(io_service, *port, *address,
checkin, lookup, answer);
} else {
dns_service = new DNSService(io_service, *port, use_ipv4,
use_ipv6, checkin, lookup,
answer);
}
DNSService dns_service(io_service, checkin, lookup, answer);
auth_server->setDNSService(dns_service);
cout << "[b10-auth] DNSServices created." << endl;
cc_session = new Session(io_service.get_io_service());
......@@ -237,7 +187,6 @@ main(int argc, char* argv[]) {
cout << "[b10-auth] Server started." << endl;
io_service.run();
delete dns_service;
} catch (const std::exception& ex) {
cerr << "[b10-auth] Server failed: " << ex.what() << endl;
ret = 1;
......
......@@ -45,6 +45,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
endif
......
......@@ -26,6 +26,8 @@
#include <dns/rrttl.h>
#include <dns/rdataclass.h>
#include <server_common/portconfig.h>
#include <datasrc/memory_datasrc.h>
#include <auth/auth_srv.h>
#include <auth/common.h>
......@@ -34,6 +36,7 @@
#include <dns/tests/unittest_util.h>
#include <testutils/dnsmessage_test.h>
#include <testutils/srv_test.h>
#include <testutils/portconfig.h>
using namespace std;
using namespace isc::cc;
......@@ -43,6 +46,7 @@ using namespace isc::data;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::testutils;
using namespace isc::server_common::portconfig;
using isc::UnitTestUtil;
namespace {
......@@ -55,7 +59,12 @@ const char* const BADCONFIG_TESTDB =
class AuthSrvTest : public SrvTestBase {
protected:
AuthSrvTest() : server(true, xfrout), rrclass(RRClass::IN()) {
AuthSrvTest() :
dnss_(ios_, NULL, NULL, NULL),
server(true, xfrout),
rrclass(RRClass::IN())
{
server.setDNSService(dnss_);
server.setXfrinSession(&notify_session);
server.setStatisticsSession(&statistics_session);
}
......@@ -63,6 +72,8 @@ protected:
server.processMessage(*io_message, parse_message, response_obuffer,
&dnsserv);
}
IOService ios_;
DNSService dnss_;
MockSession statistics_session;
MockXfroutClient xfrout;
AuthSrv server;
......@@ -650,4 +661,9 @@ TEST_F(AuthSrvTest, stop) {
// If/when the interval timer has finer granularity we'll probably add
// our own tests here, so we keep this empty test case.
}
TEST_F(AuthSrvTest, listenAddresses) {
isc::testutils::portconfig::listenAddresses(server);
}
}
......@@ -30,6 +30,7 @@
#include <auth/common.h>
#include <testutils/mockups.h>
#include <testutils/portconfig.h>
using namespace isc::dns;
using namespace isc::data;
......@@ -39,7 +40,15 @@ using namespace asiolink;
namespace {
class AuthConfigTest : public ::testing::Test {
protected:
AuthConfigTest() : rrclass(RRClass::IN()), server(true, xfrout) {}
AuthConfigTest() :
dnss_(ios_, NULL, NULL, NULL),
rrclass(RRClass::IN()),
server(true, xfrout)
{
server.setDNSService(dnss_);
}
IOService ios_;
DNSService dnss_;
const RRClass rrclass;
MockXfroutClient xfrout;
AuthSrv server;
......@@ -112,6 +121,17 @@ TEST_F(AuthConfigTest, exceptionFromCommit) {
FatalError);
}
// Test invalid address configs are rejected
TEST_F(AuthConfigTest, invalidListenAddressConfig) {
// This currently passes simply because the config doesn't know listen_on
isc::testutils::portconfig::invalidListenAddressConfig(server);
}
// Try setting addresses trough config
TEST_F(AuthConfigTest, listenAddressConfig) {
isc::testutils::portconfig::listenAddressConfig(server);
}
class MemoryDatasrcConfigTest : public AuthConfigTest {
protected:
MemoryDatasrcConfigTest() :
......
......@@ -194,8 +194,8 @@ class CChannelConnectError(Exception): pass
class BoB:
"""Boss of BIND class."""
def __init__(self, msgq_socket_file=None, dns_port=5300, address=None,
nocache=False, verbose=False, setuid=None, username=None):
def __init__(self, msgq_socket_file=None, nocache=False, verbose=False,
setuid=None, username=None):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
......@@ -203,8 +203,6 @@ class BoB:
msgq process listens on. If verbose is True, then the boss reports
what it is doing.
"""
self.address = address
self.dns_port = dns_port
self.cc_session = None
self.ccs = None
self.cfg_start_auth = True
......@@ -462,9 +460,6 @@ class BoB:
Start the Authoritative server
"""
authargs = ['b10-auth']
authargs += ['-p', str(self.dns_port)]
if self.address:
authargs += ['-a', str(self.address)]
if self.nocache:
authargs += ['-n']
if self.uid:
......@@ -473,8 +468,7 @@ class BoB:
authargs += ['-v']
# ... and start
self.start_process("b10-auth", authargs, c_channel_env,
self.dns_port, self.address)
self.start_process("b10-auth", authargs, c_channel_env)
def start_resolver(self, c_channel_env):
"""
......@@ -787,28 +781,6 @@ def fatal_signal(signal_number, stack_frame):
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
boss_of_bind.runnable = False
def check_port(option, opt_str, value, parser):
"""Function to insure that the port we are passed is actually
a valid port number. Used by OptionParser() on startup."""
try:
if opt_str in ['-p', '--port']:
parser.values.dns_port = isc.net.parse.port_parse(value)
else:
raise OptionValueError("Unknown option " + opt_str)
except ValueError as e:
raise OptionValueError(str(e))
def check_addr(option, opt_str, value, parser):
"""Function to insure that the address we are passed is actually
a valid address. Used by OptionParser() on startup."""
try:
if opt_str in ['-a', '--address']:
parser.values.address = isc.net.parse.addr_parse(value)
else:
raise OptionValueError("Unknown option " + opt_str)
except ValueError:
raise OptionValueError("%s requires a valid IPv4 or IPv6 address" % opt_str)
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)
......@@ -821,17 +793,11 @@ def main():
# Parse any command-line options.
parser = OptionParser(version=VERSION)
parser.add_option("-a", "--address", dest="address", type="string",
action="callback", callback=check_addr, default=None,
help="address the DNS server will use (default: listen on all addresses)")
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("-p", "--port", dest="dns_port", type="int",
action="callback", callback=check_port, default=5300,
help="port the DNS server will use (default 5300)")
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",
......@@ -892,9 +858,8 @@ def main():
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
# Go bob!
boss_of_bind = BoB(options.msgq_socket_file, options.dns_port,
options.address, options.nocache, options.verbose,
setuid, username)
boss_of_bind = BoB(options.msgq_socket_file, options.nocache,
options.verbose, setuid, username)
startup_result = boss_of_bind.startup()
if startup_result:
sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
......
......@@ -20,7 +20,7 @@
<refentry>
<refentryinfo>
<date>July 29, 2010</date>