From ac7c366608439a7d8e79630a469c3460e11c8355 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 13:46:16 +0900
Subject: [PATCH 001/199] [2158] updated the specification file of Xfrout
added a definition of per-zone counters: notifyoutv4, notifyoutv6, xfrrej, and
xfrreqdone.
---
src/bin/xfrout/xfrout.spec.pre.in | 59 +++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/src/bin/xfrout/xfrout.spec.pre.in b/src/bin/xfrout/xfrout.spec.pre.in
index 6b113b0bf2..c59dee854c 100644
--- a/src/bin/xfrout/xfrout.spec.pre.in
+++ b/src/bin/xfrout/xfrout.spec.pre.in
@@ -114,6 +114,65 @@
"item_default": "IN"
} ]
}
+ ],
+ "statistics": [
+ {
+ "item_name": "zones",
+ "item_type": "named_set",
+ "item_optional": false,
+ "item_default": {
+ "_SERVER_" : {
+ "notifyoutv4" : 0,
+ "notifyoutv6" : 0,
+ "xfrrej" : 0,
+ "xfrreqdone" : 0
+ }
+ },
+ "item_title": "Zone names",
+ "item_description": "Zone names for Xfrout statistics",
+ "named_set_item_spec": {
+ "item_name": "zonename",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "item_title": "Zone name",
+ "item_description": "Zone name for Xfrout statistics",
+ "map_item_spec": [
+ {
+ "item_name": "notifyoutv4",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "IPv4 notifies",
+ "item_description": "Number of IPv4 notifies per zone name sent out from Xfrout"
+ },
+ {
+ "item_name": "notifyoutv6",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "IPv6 notifies",
+ "item_description": "Number of IPv6 notifies per zone name sent out from Xfrout"
+ },
+ {
+ "item_name": "xfrrej",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "XFR rejected requests",
+ "item_description": "Number of XFR requests per zone name rejected by Xfrout"
+ },
+ {
+ "item_name": "xfrreqdone",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 0,
+ "item_title": "Requested zone transfers",
+ "item_description": "Number of requested zone transfers completed per zone name"
+ }
+ ]
+ }
+ }
]
}
}
From 9db438071c5319ed0a09cbb16da88de67a2101be Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 13:50:52 +0900
Subject: [PATCH 002/199] [2158] added a new message id for logging
It would be logged when b10-xfrout receives the "getstats" command from the
b10-stats daemon.
---
src/bin/xfrout/xfrout_messages.mes | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index 9f674a2cf8..bef6080ba1 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -107,6 +107,10 @@ received from the configuration manager.
The xfrout daemon received a command on the command channel that
NOTIFY packets should be sent for the given zone.
+% XFROUT_RECEIVED_GETSTATS_COMMAND received command to get statistics data
+The xfrout daemon received a command on the command channel that
+statistics data should be sent to the stats daemon.
+
% XFROUT_PARSE_QUERY_ERROR error parsing query: %1
There was a parse error while reading an incoming query. The parse
error is shown in the log message. A remote client sent a packet we
From 9acbaae908b7aac9123deb5dfa08e199aff4ba8e Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 15:38:18 +0900
Subject: [PATCH 003/199] [2158] updated for counting xfr requests
- added the new class XfroutCounter
It is intended for producing incrementers of the counters based on the
statistics spec and for outputting statistics data format to passed to the
b10-stats daemon.
- added counter handlers passed to the NotifyOut object and the XfroutSession
object
- added handling of the getstats command
- added counting xfr requests in the XfroutSession class
- updated the UnixSockServer class for taking over the counter handlers
---
src/bin/xfrout/xfrout.py.in | 157 +++++++++++++++++++++++++++++++++---
1 file changed, 148 insertions(+), 9 deletions(-)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index 6576432d78..3d1801e39a 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -153,7 +153,8 @@ def get_soa_serial(soa_rdata):
class XfroutSession():
def __init__(self, sock_fd, request_data, server, tsig_key_ring, remote,
- default_acl, zone_config, client_class=DataSourceClient):
+ default_acl, zone_config, client_class=DataSourceClient,
+ counter_xfrrej=None, counter_xfrreqdone=None):
self._sock_fd = sock_fd
self._request_data = request_data
self._server = server
@@ -168,6 +169,14 @@ class XfroutSession():
self.ClientClass = client_class # parameterize this for testing
self._soa = None # will be set in _xfrout_setup or in tests
self._jnl_reader = None # will be set to a reader for IXFR
+ # Set counter handlers for counting Xfr requests. An argument
+ # is required for zone name.
+ self._counter_xfrrej = lambda x: None
+ if hasattr(counter_xfrrej, '__call__'):
+ self._counter_xfrrej = counter_xfrrej
+ self._counter_xfrreqdone = lambda x: None
+ if hasattr(counter_xfrreqdone, '__call__'):
+ self._counter_xfrreqdone = counter_xfrreqdone
self._handle()
def create_tsig_ctx(self, tsig_record, tsig_key_ring):
@@ -270,6 +279,8 @@ class XfroutSession():
format_zone_str(zone_name, zone_class))
return None, None
elif acl_result == REJECT:
+ # count rejected Xfr request by each zone name
+ self._counter_xfrrej(zone_name.to_text())
logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
self._request_type, format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
@@ -525,6 +536,8 @@ class XfroutSession():
except Exception as err:
logger.error(XFROUT_XFR_TRANSFER_ERROR, self._request_typestr,
format_addrinfo(self._remote), zone_str, err)
+ # count done Xfr requests by each zone name
+ self._counter_xfrreqdone(zone_name.to_text())
logger.info(XFROUT_XFR_TRANSFER_DONE, self._request_typestr,
format_addrinfo(self._remote), zone_str)
@@ -634,7 +647,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
'''The unix domain socket server which accept xfr query sent from auth server.'''
def __init__(self, sock_file, handle_class, shutdown_event, config_data,
- cc):
+ cc, **counters):
self._remove_unused_sock_file(sock_file)
self._sock_file = sock_file
socketserver_mixin.NoPollMixIn.__init__(self)
@@ -644,6 +657,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
self._common_init()
self._cc = cc
self.update_config_data(config_data)
+ # handlers for statistics use
+ self._counters = counters
def _common_init(self):
'''Initialization shared with the mock server class used for tests'''
@@ -798,7 +813,8 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
self._lock.release()
self.RequestHandlerClass(sock_fd, request_data, self,
isc.server_common.tsig_keyring.get_keyring(),
- self._guess_remote(sock_fd), acl, zone_config)
+ self._guess_remote(sock_fd), acl, zone_config,
+ **self._counters)
def _remove_unused_sock_file(self, sock_file):
'''Try to remove the socket file. If the file is being used
@@ -926,6 +942,109 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
self._transfers_counter -= 1
self._lock.release()
+class XfroutCounter:
+ """A class for handling all statistics counters of Xfrout. In
+ this class, the structure of per-zone counters is assumed to be
+ like this:
+ zones/example.com./notifyoutv4
+ zones/example.com./notifyoutv6
+ zones/example.com./xfrrej
+ zones/example.com./xfrreqdone
+ """
+ # '_SERVER_' is a special zone name representing an entire
+ # count. It doesn't mean a specific zone, but it means an
+ # entire count in the server.
+ entire_server = '_SERVER_'
+ # zone names are contained under this dirname in the spec file.
+ perzone_prefix = 'zones'
+ def __init__(self, statistics_spec):
+ self._statistics_spec = statistics_spec
+ # holding statistics data for Xfrout module
+ self._statistics_data = {}
+ self._lock = threading.RLock()
+ self._create_perzone_incrementers()
+
+ def get_statistics(self):
+ """Calculates an entire server counts, and returns statistics
+ data format to send out the stats module including each
+ counter. If there is no counts, then it returns an empty
+ dictionary. Locks the thread because it is considered to be
+ invoked by a multi-threading caller."""
+ # If self._statistics_data contains nothing of zone name, it
+ # returns an empty dict.
+ if len(self._statistics_data) == 0: return {}
+ zones = {}
+ with self._lock:
+ zones = self._statistics_data[self.perzone_prefix].copy()
+ # Start calculation for '_SERVER_' counts
+ attrs = self._get_default_statistics_data()[self.perzone_prefix][self.entire_server]
+ statistics_data = {self.perzone_prefix: {}}
+ for attr in attrs:
+ sum_ = 0
+ for name in zones:
+ if name == self.entire_server: continue
+ if attr in zones[name]:
+ if name not in statistics_data[self.perzone_prefix]:
+ statistics_data[self.perzone_prefix][name] = {}
+ statistics_data[self.perzone_prefix][name].update(
+ {attr: zones[name][attr]}
+ )
+ sum_ += zones[name][attr]
+ if sum_ > 0:
+ if self.entire_server not in statistics_data[self.perzone_prefix]:
+ statistics_data[self.perzone_prefix][self.entire_server] = {}
+ statistics_data[self.perzone_prefix][self.entire_server].update({attr: sum_})
+ return statistics_data
+
+ def _get_default_statistics_data(self):
+ """Returns default statistics data from the spec file"""
+ statistics_data = {}
+ for id_ in isc.config.spec_name_list(self._statistics_spec):
+ spec = isc.config.find_spec_part(self._statistics_spec, id_)
+ statistics_data.update({id_: spec['item_default']})
+ return statistics_data
+
+ def _create_perzone_incrementers(self):
+ """Creates increment method of each per-zone counter based on
+ the spec file. Incrementer can be accessed by name
+ "inc_${item_name}".Incrementers are passed to the
+ XfroutSession and NotifyOut class as counter handlers."""
+ # add a new element under the named_set item for the zone
+ zones_spec = isc.config.find_spec_part(
+ self._statistics_spec, self.perzone_prefix)
+ item_list = isc.config.spec_name_list(\
+ zones_spec['named_set_item_spec']['map_item_spec'])
+ # can be accessed by the name 'inc_xxx'
+ for item in item_list:
+ def __perzone_incrementer(zone_name, counter_name=item, step=1):
+ """A per-zone incrementer for counter_name. Locks the thread
+ because it is considered to be invoked by a multi-threading
+ caller."""
+ with self._lock:
+ self._add_perzone_counter(zone_name)
+ self._statistics_data[self.perzone_prefix][zone_name][counter_name] += step
+ #def __perzone_incrementer(zone_name, counter_name=item):
+ # self._perzone_incrementer(zone_name, counter_name)
+ setattr(self, 'inc_%s' % item, __perzone_incrementer)
+
+
+ def _add_perzone_counter(self, zone):
+ """Adds named_set-type counter for each zone name"""
+ try:
+ self._statistics_data[self.perzone_prefix][zone]
+ except KeyError:
+ # add a new element under the named_set item for the zone
+ map_spec = isc.config.find_spec_part(
+ self._statistics_spec, '%s/%s' % \
+ (self.perzone_prefix, zone))['map_item_spec']
+ id_list = isc.config.spec_name_list(map_spec)
+ for id_ in id_list:
+ spec = isc.config.find_spec_part(map_spec, id_)
+ isc.cc.data.set(self._statistics_data,
+ '%s/%s/%s' % \
+ (self.perzone_prefix, zone, id_),
+ spec['item_default'])
+
class XfroutServer:
def __init__(self):
self._unix_socket_server = None
@@ -933,6 +1052,8 @@ class XfroutServer:
self._shutdown_event = threading.Event()
self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
self._config_data = self._cc.get_full_config()
+ self._counter = XfroutCounter(
+ self._cc.get_module_spec().get_statistics_spec())
self._cc.start()
self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
isc.server_common.tsig_keyring.init_keyring(self._cc)
@@ -941,17 +1062,25 @@ class XfroutServer:
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._cc)
+ self._unix_socket_server = UnixSockServer(
+ self._listen_sock_file,
+ XfroutSession,
+ self._shutdown_event,
+ self._config_data,
+ self._cc,
+ counter_xfrrej=self._counter.inc_xfrrej,
+ counter_xfrreqdone=self._counter.inc_xfrreqdone
+ )
listener = threading.Thread(target=self._unix_socket_server.serve_forever)
listener.start()
def _start_notifier(self):
datasrc = self._unix_socket_server.get_db_file()
- self._notifier = notify_out.NotifyOut(datasrc)
+ self._notifier = notify_out.NotifyOut(
+ datasrc,
+ counter_notifyoutv4=self._counter.inc_notifyoutv4,
+ counter_notifyoutv6=self._counter.inc_notifyoutv6
+ )
if 'also_notify' in self._config_data:
for slave in self._config_data['also_notify']:
self._notifier.add_slave(slave['address'], slave['port'])
@@ -1027,6 +1156,16 @@ class XfroutServer:
else:
answer = create_answer(1, "Bad command parameter:" + str(args))
+ # return statistics data to the stats daemon
+ elif cmd == "getstats":
+ # The log level is here set to debug in order to avoid
+ # that a log becomes too verbose. Because the b10-stats
+ # daemon is periodically asking to the b10-xfrout daemon.
+ logger.debug(DBG_XFROUT_TRACE, \
+ XFROUT_RECEIVED_GETSTATS_COMMAND)
+ answer = isc.config.ccsession.create_answer(
+ 0, self._counter.get_statistics())
+
else:
answer = create_answer(1, "Unknown command:" + str(cmd))
From b6bba799f9422b6bc0003bc2e34d9bdc1fa9da67 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 14:10:54 +0900
Subject: [PATCH 004/199] [2158] updated unittest of Xfrout
- updated the mock classes for testing counters
- added tests checking each counter exactly incrementing
- added tests for the XfroutCounter class
- added a test for handling the getstats command
---
src/bin/xfrout/tests/xfrout_test.py.in | 100 ++++++++++++++++++++++++-
1 file changed, 99 insertions(+), 1 deletion(-)
diff --git a/src/bin/xfrout/tests/xfrout_test.py.in b/src/bin/xfrout/tests/xfrout_test.py.in
index e4fc873e46..39ac2df2b8 100644
--- a/src/bin/xfrout/tests/xfrout_test.py.in
+++ b/src/bin/xfrout/tests/xfrout_test.py.in
@@ -277,13 +277,23 @@ class TestXfroutSessionBase(unittest.TestCase):
# When not testing ACLs, simply accept
isc.acl.dns.REQUEST_LOADER.load(
[{"action": "ACCEPT"}]),
- {})
+ {},
+ counter_xfrrej=self._counter_xfrrej,
+ counter_xfrreqdone=self._counter_xfrreqdone)
self.set_request_type(RRType.AXFR()) # test AXFR by default
self.mdata = self.create_request_data()
self.soa_rrset = create_soa(SOA_CURRENT_VERSION)
# some test replaces a module-wide function. We should ensure the
# original is used elsewhere.
self.orig_get_rrset_len = xfrout.get_rrset_len
+ self._zone_name_xfrrej = None
+ self._zone_name_xfrreqdone = None
+
+ def _counter_xfrrej(self, zone_name):
+ self._zone_name_xfrrej = zone_name
+
+ def _counter_xfrreqdone(self, zone_name):
+ self._zone_name_xfrreqdone = zone_name
def tearDown(self):
xfrout.get_rrset_len = self.orig_get_rrset_len
@@ -458,7 +468,9 @@ class TestXfroutSession(TestXfroutSessionBase):
# ACL checks only with the default ACL
def acl_setter(acl):
self.xfrsess._acl = acl
+ self.assertIsNone(self._zone_name_xfrrej)
self.check_transfer_acl(acl_setter)
+ self.assertEqual(self._zone_name_xfrrej, TEST_ZONE_NAME_STR)
def test_transfer_zoneacl(self):
# ACL check with a per zone ACL + default ACL. The per zone ACL
@@ -469,7 +481,9 @@ class TestXfroutSession(TestXfroutSessionBase):
self.xfrsess._zone_config[zone_key]['transfer_acl'] = acl
self.xfrsess._acl = isc.acl.dns.REQUEST_LOADER.load([
{"from": "127.0.0.1", "action": "DROP"}])
+ self.assertIsNone(self._zone_name_xfrrej)
self.check_transfer_acl(acl_setter)
+ self.assertEqual(self._zone_name_xfrrej, TEST_ZONE_NAME_STR)
def test_transfer_zoneacl_nomatch(self):
# similar to the previous one, but the per zone doesn't match the
@@ -481,7 +495,9 @@ class TestXfroutSession(TestXfroutSessionBase):
isc.acl.dns.REQUEST_LOADER.load([
{"from": "127.0.0.1", "action": "DROP"}])
self.xfrsess._acl = acl
+ self.assertIsNone(self._zone_name_xfrrej)
self.check_transfer_acl(acl_setter)
+ self.assertEqual(self._zone_name_xfrrej, TEST_ZONE_NAME_STR)
def test_get_transfer_acl(self):
# set the default ACL. If there's no specific zone ACL, this one
@@ -831,9 +847,11 @@ class TestXfroutSession(TestXfroutSessionBase):
def myreply(msg, sock):
self.sock.send(b"success")
+ self.assertIsNone(self._zone_name_xfrreqdone)
self.xfrsess._reply_xfrout_query = myreply
self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
self.assertEqual(self.sock.readsent(), b"success")
+ self.assertEqual(self._zone_name_xfrreqdone, TEST_ZONE_NAME_STR)
def test_reply_xfrout_query_axfr(self):
self.xfrsess._soa = self.soa_rrset
@@ -1153,6 +1171,7 @@ class MyUnixSockServer(UnixSockServer):
self._common_init()
self._cc = MyCCSession()
self.update_config_data(self._cc.get_full_config())
+ self._counters = {}
class TestUnixSockServer(unittest.TestCase):
def setUp(self):
@@ -1504,6 +1523,80 @@ class MyXfroutServer(XfroutServer):
self._unix_socket_server = None
# Disable the wait for threads
self._wait_for_threads = lambda : None
+ self._cc.get_module_spec = lambda:\
+ isc.config.module_spec_from_file(xfrout.SPECFILE_LOCATION)
+ # setup an XfroutCount object
+ self._counter = XfroutCounter(
+ self._cc.get_module_spec().get_statistics_spec())
+
+class TestXfroutCounter(unittest.TestCase):
+ def setUp(self):
+ statistics_spec = \
+ isc.config.module_spec_from_file(\
+ xfrout.SPECFILE_LOCATION).get_statistics_spec()
+ self.xfrout_counter = XfroutCounter(statistics_spec)
+ self._counters = isc.config.spec_name_list(\
+ isc.config.find_spec_part(\
+ statistics_spec, XfroutCounter.perzone_prefix)\
+ ['named_set_item_spec']['map_item_spec'])
+ self._started = threading.Event()
+ self._number = 3 # number of the threads
+ self._cycle = 10000 # number of counting per thread
+
+ def test_get_default_statistics_data(self):
+ self.assertEqual(self.xfrout_counter._get_default_statistics_data(),
+ {XfroutCounter.perzone_prefix: {
+ XfroutCounter.entire_server: \
+ dict([(cnt, 0) for cnt in self._counters])
+ }})
+
+ def setup_incrementer(self, incrementer):
+ self._started.wait()
+ for i in range(self._cycle): incrementer(TEST_ZONE_NAME_STR)
+
+ def start_incrementer(self, incrementer):
+ threads = []
+ for i in range(self._number):
+ threads.append(threading.Thread(\
+ target=self.setup_incrementer,\
+ args=(incrementer,)\
+ ))
+ for th in threads: th.start()
+ self._started.set()
+ for th in threads: th.join()
+
+ def get_count(self, zone_name, counter_name):
+ return isc.cc.data.find(\
+ self.xfrout_counter.get_statistics(),\
+ '%s/%s/%s' % (XfroutCounter.perzone_prefix,\
+ zone_name, counter_name))
+
+ def test_incrementers(self):
+ result = { XfroutCounter.entire_server: {},
+ TEST_ZONE_NAME_STR: {} }
+ for counter_name in self._counters:
+ incrementer = getattr(self.xfrout_counter, 'inc_%s' % counter_name)
+ self.start_incrementer(incrementer)
+ self.assertEqual(self.get_count(\
+ TEST_ZONE_NAME_STR, counter_name), \
+ self._number * self._cycle)
+ self.assertEqual(self.get_count(\
+ XfroutCounter.entire_server, counter_name), \
+ self._number * self._cycle)
+ result[XfroutCounter.entire_server][counter_name] = \
+ result[TEST_ZONE_NAME_STR][counter_name] = \
+ self._number * self._cycle
+ self.assertEqual(
+ self.xfrout_counter.get_statistics(),
+ {XfroutCounter.perzone_prefix: result})
+
+ def test_add_perzone_counter(self):
+ for counter_name in self._counters:
+ self.assertRaises(isc.cc.data.DataNotFoundError,\
+ self.get_count, TEST_ZONE_NAME_STR, counter_name)
+ self.xfrout_counter._add_perzone_counter(TEST_ZONE_NAME_STR)
+ for counter_name in self._counters:
+ self.assertEqual(self.get_count(TEST_ZONE_NAME_STR, counter_name), 0)
class TestXfroutServer(unittest.TestCase):
def setUp(self):
@@ -1514,6 +1607,11 @@ class TestXfroutServer(unittest.TestCase):
self.assertTrue(self.xfrout_server._notifier.shutdown_called)
self.assertTrue(self.xfrout_server._cc.stopped)
+ def test_getstats(self):
+ self.assertEqual(
+ self.xfrout_server.command_handler('getstats', None),
+ isc.config.ccsession.create_answer(0, {}))
+
if __name__== "__main__":
isc.log.resetUnitTestRootLogger()
unittest.main()
From f483892f37e50ed1a0afe0cc4e1e4f5a1f58a035 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 15:40:07 +0900
Subject: [PATCH 005/199] [2158] updated the NotifyOut class for counting
notifications
- added setting up the counter handlers for IPv4 and IPv6
- added counting notifications in the NotifyOut class
- fixed a trivial typo
---
src/lib/python/isc/notify/notify_out.py | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 34db14c5c3..8d632d06ef 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -125,9 +125,10 @@ class ZoneNotifyInfo:
class NotifyOut:
'''This class is used to handle notify logic for all zones(sending
notify message to its slaves). notify service can be started by
- calling dispatcher(), and it can be stoped by calling shutdown()
+ calling dispatcher(), and it can be stopped by calling shutdown()
in another thread. '''
- def __init__(self, datasrc_file, verbose=True):
+ def __init__(self, datasrc_file, counter_handler=None, verbose=True,
+ counter_notifyoutv4=None, counter_notifyoutv6=None):
self._notify_infos = {} # key is (zone_name, zone_class)
self._waiting_zones = []
self._notifying_zones = []
@@ -142,6 +143,14 @@ class NotifyOut:
# Use nonblock event to eliminate busy loop
# If there are no notifying zones, clear the event bit and wait.
self._nonblock_event = threading.Event()
+ # Set counter handlers for counting notifies. An argument is
+ # required for zone name.
+ self._counter_notifyoutv4 = lambda x: None
+ if hasattr(counter_notifyoutv4, '__call__'):
+ self._counter_notifyoutv4 = counter_notifyoutv4
+ self._counter_notifyoutv6 = lambda x: None
+ if hasattr(counter_notifyoutv6, '__call__'):
+ self._counter_notifyoutv6 = counter_notifyoutv6
def _init_notify_out(self, datasrc_file):
'''Get all the zones name and its notify target's address.
@@ -478,6 +487,11 @@ class NotifyOut:
try:
sock = zone_notify_info.create_socket(addrinfo[0])
sock.sendto(render.get_data(), 0, addrinfo)
+ # count notifying by IPv4 or IPv6 for statistics
+ if zone_notify_info.get_socket().family == socket.AF_INET:
+ self._counter_notifyoutv4(zone_notify_info.zone_name)
+ elif zone_notify_info.get_socket().family == socket.AF_INET6:
+ self._counter_notifyoutv6(zone_notify_info.zone_name)
logger.info(NOTIFY_OUT_SENDING_NOTIFY, addrinfo[0],
addrinfo[1])
except (socket.error, addr.InvalidAddress) as err:
From d3bc2109f07fac785c5a75041f4e88696dbc6a33 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 14:20:08 +0900
Subject: [PATCH 006/199] [2158] updated unittest for checking the notification
counters
- updated the mock classes for testing counters
- added tests of each counter with a specified zone name
---
.../isc/notify/tests/notify_out_test.py | 21 ++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index 1b3a4a128d..8343d0bf53 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -61,6 +61,7 @@ class MockZoneNotifyInfo(notify_out.ZoneNotifyInfo):
self.sock_family = self._sock.family
self._sock.close()
self._sock = MockSocket()
+ self._sock.family = self.sock_family
return self._sock
class TestZoneNotifyInfo(unittest.TestCase):
@@ -95,7 +96,13 @@ class TestZoneNotifyInfo(unittest.TestCase):
class TestNotifyOut(unittest.TestCase):
def setUp(self):
self._db_file = TESTDATA_SRCDIR + '/test.sqlite3'
- self._notify = notify_out.NotifyOut(self._db_file)
+ self._notifiedv4_zone_name = None
+ def _dummy_counter_notifyoutv4(z): self._notifiedv4_zone_name = z
+ self._notifiedv6_zone_name = None
+ def _dummy_counter_notifyoutv6(z): self._notifiedv6_zone_name = z
+ self._notify = notify_out.NotifyOut(self._db_file,
+ counter_notifyoutv4=_dummy_counter_notifyoutv4,
+ counter_notifyoutv6=_dummy_counter_notifyoutv6)
self._notify._notify_infos[('example.com.', 'IN')] = MockZoneNotifyInfo('example.com.', 'IN')
self._notify._notify_infos[('example.com.', 'CH')] = MockZoneNotifyInfo('example.com.', 'CH')
self._notify._notify_infos[('example.net.', 'IN')] = MockZoneNotifyInfo('example.net.', 'IN')
@@ -262,17 +269,25 @@ class TestNotifyOut(unittest.TestCase):
def test_send_notify_message_udp_ipv4(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
example_com_info.prepare_notify_out()
+ self.assertIsNone(self._notifiedv4_zone_name)
+ self.assertIsNone(self._notifiedv6_zone_name)
ret = self._notify._send_notify_message_udp(example_com_info,
('192.0.2.1', 53))
self.assertTrue(ret)
self.assertEqual(socket.AF_INET, example_com_info.sock_family)
+ self.assertEqual(self._notifiedv4_zone_name, 'example.net.')
+ self.assertIsNone(self._notifiedv6_zone_name)
def test_send_notify_message_udp_ipv6(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
+ self.assertIsNone(self._notifiedv4_zone_name)
+ self.assertIsNone(self._notifiedv6_zone_name)
ret = self._notify._send_notify_message_udp(example_com_info,
('2001:db8::53', 53))
self.assertTrue(ret)
self.assertEqual(socket.AF_INET6, example_com_info.sock_family)
+ self.assertIsNone(self._notifiedv4_zone_name)
+ self.assertEqual(self._notifiedv6_zone_name, 'example.net.')
def test_send_notify_message_with_bogus_address(self):
example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
@@ -281,9 +296,13 @@ class TestNotifyOut(unittest.TestCase):
# happen, but right now it's not actually the case. Even if the
# data source does its job, it's prudent to confirm the behavior for
# an unexpected case.
+ self.assertIsNone(self._notifiedv4_zone_name)
+ self.assertIsNone(self._notifiedv6_zone_name)
ret = self._notify._send_notify_message_udp(example_com_info,
('invalid', 53))
self.assertFalse(ret)
+ self.assertIsNone(self._notifiedv4_zone_name)
+ self.assertIsNone(self._notifiedv6_zone_name)
def test_zone_notify_handler(self):
old_send_msg = self._notify._send_notify_message_udp
From 9007b87d062335814cbef0b579003a61d6442e57 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 14:33:56 +0900
Subject: [PATCH 007/199] [2158] updated the lettuce test suite
- introduced the b10-stats daemon running in the lettuce test suite "Xfrin
incoming notify handling"
- renamed retransfer_master.conf to retransfer_master.conf.orig because of the
config change in the lettuce suite
---
tests/lettuce/configurations/xfrin/.gitignore | 1 +
.../{retransfer_master.conf => retransfer_master.conf.orig} | 1 +
tests/lettuce/features/terrain/terrain.py | 2 ++
3 files changed, 4 insertions(+)
create mode 100644 tests/lettuce/configurations/xfrin/.gitignore
rename tests/lettuce/configurations/xfrin/{retransfer_master.conf => retransfer_master.conf.orig} (93%)
diff --git a/tests/lettuce/configurations/xfrin/.gitignore b/tests/lettuce/configurations/xfrin/.gitignore
new file mode 100644
index 0000000000..4de8c4b137
--- /dev/null
+++ b/tests/lettuce/configurations/xfrin/.gitignore
@@ -0,0 +1 @@
+/retransfer_master.conf
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master.conf b/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
similarity index 93%
rename from tests/lettuce/configurations/xfrin/retransfer_master.conf
rename to tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
index dd29ac893e..b0e3ac0b88 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_master.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_master.conf.orig
@@ -38,6 +38,7 @@
"b10-auth": { "kind": "needed", "special": "auth" },
"b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
"b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
+ "b10-stats": { "address": "Stats", "kind": "dispensable" },
"b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
}
}
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index 876e7cfd48..8720e2d994 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -57,6 +57,8 @@ copylist = [
"configurations/ddns/ddns.config"],
["configurations/ddns/noddns.config.orig",
"configurations/ddns/noddns.config"],
+ ["configurations/xfrin/retransfer_master.conf.orig",
+ "configurations/xfrin/retransfer_master.conf"],
["data/inmem-xfrin.sqlite3.orig",
"data/inmem-xfrin.sqlite3"],
["data/xfrin-notify.sqlite3.orig",
From b18cb62ebeea655fcc277a2478a9ee560a33408b Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 14:42:29 +0900
Subject: [PATCH 008/199] [2158] added the lettuce step methods for statistics
- added the two step methods and a helper method
That is intended for querying statistics counters via bindctl and for
checking whether the returned values of the counters are exactly expected
ones.
---
.../features/terrain/bind10_control.py | 61 +++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/tests/lettuce/features/terrain/bind10_control.py b/tests/lettuce/features/terrain/bind10_control.py
index b661657bce..b1c8aced7a 100644
--- a/tests/lettuce/features/terrain/bind10_control.py
+++ b/tests/lettuce/features/terrain/bind10_control.py
@@ -362,3 +362,64 @@ def configure_ddns_off(step):
config commit
\"\"\"
""")
+
+@step('query statistics(?: (\S+))? of bind10 module (\S+)(?: with cmdctl port (\d+))?')
+def query_statistics(step, statistics, name, cmdctl_port):
+ """
+ query statistics data via bindctl.
+ Parameters:
+ statistics ('statistics ', optional) : The queried statistics name.
+ name ('module '): The name of the module (case sensitive!)
+ cmdctl_port ('with cmdctl port ', optional): cmdctl port to send
+ the command to.
+ """
+ port_str = ' with cmdctl port %s' % cmdctl_port \
+ if cmdctl_port else ''
+ step.given('send bind10%s the command Stats show owner=%s%s'\
+ % (port_str, name,\
+ ' name=%s' % statistics if statistics else ''))
+
+def find_value(dictionary, key):
+ """A helper method. Recursively find a value corresponding to the
+ key of the dictionary and returns it. Returns None if the
+ dictionary is not dict type."""
+ if type(dictionary) is not dict:
+ return
+ if key in dictionary:
+ return dictionary[key]
+ else:
+ for v in dictionary.values():
+ return find_value(v, key)
+
+@step('The counter (\S+)(?: for the zone (\S+))? should be' + \
+ '(?:( greater than| less than))? (\d+)')
+def check_statistics(step, counter, zone, gtlt, number):
+ """
+ check the output of bindctl for statistics of specified counter
+ and zone.
+ Parameters:
+ counter ('counter '): The counter name of statistics.
+ zone ('zone ', optional): The zone name.
+ gtlt (' greater than'|' less than', optional): greater than
+ or less than .
+ number ('): The expect counter number. is assumed
+ to be an unsigned integer.
+ """
+ output = parse_bindctl_output_as_data_structure()
+ found = None
+ zone_str = ""
+ if zone:
+ found = find_value(find_value(output, zone), counter)
+ zone_str = " for zone %s" % zone
+ else:
+ found = find_value(output, counter)
+ assert found is not None, \
+ 'Not found statistics counter %s%s' % (counter, zone_str)
+ msg = "Got %s, expected%s %s as counter %s%s" % \
+ (found, gtlt, number, counter, zone_str)
+ if gtlt and 'greater' in gtlt:
+ assert int(found) > int(number), msg
+ elif gtlt and 'less' in gtlt:
+ assert int(found) < int(number), msg
+ else:
+ assert int(found) == int(number), msg
From 314157f8af6d820c7beee0eb720951239752e008 Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 15:10:31 +0900
Subject: [PATCH 009/199] [2158] updated the xfrin_notify_handling feature
- querying each statistics counter of the b10-xfrout daemon
- checking correct values of the counters and no errors after querying
- added waiting for some events in the debug log
- added a similar scenario that xfrin requests are rejected in order to check
value of the counter xfrrej
---
.../features/xfrin_notify_handling.feature | 110 ++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/tests/lettuce/features/xfrin_notify_handling.feature b/tests/lettuce/features/xfrin_notify_handling.feature
index e514b83c1d..e0026abfd6 100644
--- a/tests/lettuce/features/xfrin_notify_handling.feature
+++ b/tests/lettuce/features/xfrin_notify_handling.feature
@@ -8,6 +8,7 @@ Feature: Xfrin incoming notify handling
And wait for master stderr message AUTH_SERVER_STARTED
And wait for master stderr message XFROUT_STARTED
And wait for master stderr message ZONEMGR_STARTED
+ And wait for master stderr message STATS_STARTING
And I have bind10 running with configuration xfrin/retransfer_slave_notify.conf
And wait for bind10 stderr message BIND10_STARTED_CC
@@ -18,6 +19,19 @@ Feature: Xfrin incoming notify handling
A query for www.example.org to [::1]:47806 should have rcode NXDOMAIN
+ #
+ # Test for statistics
+ #
+ # check for initial statistics
+ #
+ When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
+ last bindctl output should not contain "error"
+ last bindctl output should not contain "example.org."
+ The counter notifyoutv4 for the zone _SERVER_ should be 0
+ The counter notifyoutv6 for the zone _SERVER_ should be 0
+ The counter xfrrej for the zone _SERVER_ should be 0
+ The counter xfrreqdone for the zone _SERVER_ should be 0
+
When I send bind10 with cmdctl port 47804 the command Xfrout notify example.org IN
Then wait for new master stderr message XFROUT_NOTIFY_COMMAND
Then wait for new bind10 stderr message AUTH_RECEIVED_NOTIFY
@@ -25,5 +39,101 @@ Feature: Xfrin incoming notify handling
Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_STARTED
Then wait for new bind10 stderr message XFRIN_TRANSFER_SUCCESS not XFRIN_XFR_PROCESS_FAILURE
Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_SUCCESS
+ Then wait 5 times for new master stderr message NOTIFY_OUT_SENDING_NOTIFY
+ Then wait for new master stderr message NOTIFY_OUT_RETRY_EXCEEDED
A query for www.example.org to [::1]:47806 should have rcode NOERROR
+
+ #
+ # Test for statistics
+ #
+ # check for statistics change
+ #
+ When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
+ last bindctl output should not contain "error"
+ Then wait for new master stderr message XFROUT_RECEIVED_GETSTATS_COMMAND
+ The counter notifyoutv4 for the zone _SERVER_ should be 0
+ The counter notifyoutv4 for the zone example.org. should be 0
+ The counter notifyoutv6 for the zone _SERVER_ should be 5
+ The counter notifyoutv6 for the zone example.org. should be 5
+ The counter xfrrej for the zone _SERVER_ should be 0
+ The counter xfrrej for the zone example.org. should be 0
+ The counter xfrreqdone for the zone _SERVER_ should be 1
+ The counter xfrreqdone for the zone example.org. should be 1
+
+ #
+ # Test for Xfr request rejected
+ #
+ Scenario: Handle incoming notify (XFR request rejected)
+ Given I have bind10 running with configuration xfrin/retransfer_master.conf with cmdctl port 47804 as master
+ And wait for master stderr message BIND10_STARTED_CC
+ And wait for master stderr message CMDCTL_STARTED
+ And wait for master stderr message AUTH_SERVER_STARTED
+ And wait for master stderr message XFROUT_STARTED
+ And wait for master stderr message ZONEMGR_STARTED
+ And wait for master stderr message STATS_STARTING
+
+ And I have bind10 running with configuration xfrin/retransfer_slave_notify.conf
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+ And wait for bind10 stderr message XFRIN_STARTED
+ And wait for bind10 stderr message ZONEMGR_STARTED
+
+ A query for www.example.org to [::1]:47806 should have rcode NXDOMAIN
+
+ #
+ # Test1 for statistics
+ #
+ # check for initial statistics
+ #
+ When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
+ last bindctl output should not contain "error"
+ last bindctl output should not contain "example.org."
+ The counter notifyoutv4 for the zone _SERVER_ should be 0
+ The counter notifyoutv6 for the zone _SERVER_ should be 0
+ The counter xfrrej for the zone _SERVER_ should be 0
+ The counter xfrreqdone for the zone _SERVER_ should be 0
+
+ #
+ # set transfer_acl rejection
+ # Local xfr requests from Xfrin module would be rejected here.
+ #
+ When I send bind10 the following commands with cmdctl port 47804
+ """
+ config set Xfrout/zone_config[0]/transfer_acl [{"action": "REJECT", "from": "::1"}]
+ config commit
+ """
+ last bindctl output should not contain Error
+
+ When I send bind10 with cmdctl port 47804 the command Xfrout notify example.org IN
+ Then wait for new master stderr message XFROUT_NOTIFY_COMMAND
+ Then wait for new bind10 stderr message AUTH_RECEIVED_NOTIFY
+ Then wait for new bind10 stderr message ZONEMGR_RECEIVE_NOTIFY
+ Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_STARTED
+ Then wait for new bind10 stderr message XFRIN_XFR_TRANSFER_PROTOCOL_ERROR not XFRIN_XFR_TRANSFER_STARTED
+ Then wait for new bind10 stderr message ZONEMGR_RECEIVE_XFRIN_FAILED not ZONEMGR_RECEIVE_XFRIN_SUCCESS
+ Then wait 5 times for new master stderr message NOTIFY_OUT_SENDING_NOTIFY
+ Then wait for new master stderr message NOTIFY_OUT_RETRY_EXCEEDED
+
+ A query for www.example.org to [::1]:47806 should have rcode NXDOMAIN
+
+ #
+ # Test2 for statistics
+ #
+ # check for statistics change
+ #
+ When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
+ last bindctl output should not contain "error"
+ The counter notifyoutv4 for the zone _SERVER_ should be 0
+ The counter notifyoutv4 for the zone example.org. should be 0
+ The counter notifyoutv6 for the zone _SERVER_ should be 5
+ The counter notifyoutv6 for the zone example.org. should be 5
+ # The counts of rejection would be between 1 and 2. They are not
+ # fixed. It would depend on timing or the platform.
+ The counter xfrrej for the zone _SERVER_ should be greater than 0
+ The counter xfrrej for the zone _SERVER_ should be less than 3
+ The counter xfrrej for the zone example.org. should be greater than 0
+ The counter xfrrej for the zone example.org. should be less than 3
+ The counter xfrreqdone for the zone _SERVER_ should be 0
+ The counter xfrreqdone for the zone example.org. should be 0
From 302762af537cb1a570f1d803702495b2fea2a98f Mon Sep 17 00:00:00 2001
From: Naoki Kambe
Date: Fri, 17 Aug 2012 15:12:23 +0900
Subject: [PATCH 010/199] [2158] updated the manpage of b10-xfrout
- added statistics counters and their descriptions
- added description about the zone name "_SERVER_"
---
src/bin/xfrout/b10-xfrout.xml | 48 +++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/src/bin/xfrout/b10-xfrout.xml b/src/bin/xfrout/b10-xfrout.xml
index f79a42d08f..4415cffb78 100644
--- a/src/bin/xfrout/b10-xfrout.xml
+++ b/src/bin/xfrout/b10-xfrout.xml
@@ -153,6 +153,54 @@
+
+ STATISTICS DATA
+
+
+ The statistics data collected by the b10-xfrout
+ daemon for Xfrout
include:
+
+
+
+
+
+ notifyoutv4
+
+ Number of IPv4 notifies per zone name sent out from Xfrout
+
+
+
+
+ notifyoutv6
+
+ Number of IPv6 notifies per zone name sent out from Xfrout
+
+
+
+
+ xfrrej
+
+ Number of XFR requests per zone name rejected by Xfrout
+
+
+
+
+ xfrreqdone
+
+ Number of requested zone transfers per zone name completed
+
+
+
+
+
+
+ In per-zone counters the special zone name '_SERVER_' exists. It doesn't
+ mean a specific zone. It represents an entire server and its value means
+ a total count of all zones.
+
+
+
+
-
-
+
+
DHCP Performance Guide
@@ -37,7 +37,10 @@
Tomasz
Mrugalski
-
+
+ Marcin
+ Siodelski
+
BIND 10 is a framework that features Domain Name System
(DNS) suite and Dynamic Host Configuration Protocol (DHCP)
@@ -586,9 +589,252 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
perfdhcp
-
- TODO: Write something about perfdhcp here.
-
-
+
+ Purpose
+
+ There is a growing need to evaluate performance of DHCP servers in
+ different traffic conditions to understand their bottle necks.
+ This helps to elimante bugs in existing DHCP software as well
+ as make informed decisions regarding new DHCP software designs
+ to significantly improve its performance. The perfdhcp tool has
+ been created to fill the gap in performance measurement capabilities
+ mostly. However, the number of implemented features and parameters
+ exposed to the user make this tool useful for functional testing as
+ well.
+
+
+
+ Key features
+
+ The perfdhcp exposes the number of command line parameters to
+ control DHCP message exchanges. Currently they fall back to
+ the following categories:
+
+
+
+ Rate control - control how many DHCP exchanges
+ are initiated within a period of time. Tool can also simulate
+ best effort conditions where it attempts to start as many
+ exchanges as possible.
+
+
+
+
+ Test exit specifiers - control the conditions when test
+ completes including number of initiated exchanges, test period or
+ maximum number of dropped packets.
+
+
+
+
+ Packet templates - specify files containing packet templates that
+ are used by perfdhcp to create custom DHCP messages instead of
+ default. Tool also allows to specify number of values indicating
+ offsets of variable values within a packet that are modified in
+ flight by the tool.
+
+
+
+
+ Reporting - for each test produce the set of performance data
+ including achieved packet exchange rate (server performance).
+ There is also a number of diagnostic selectors available that
+ enable periodic (intermediate) reporting, packet timestamps
+ printing and detailed information about perfdhcp internal
+ states (for debugging).
+
+
+
+
+ Different mode of operations - specify DHCP version used
+ (v4 or v6), 2-way or 4-way exchanges, use Rapid Commit option
+ for DHCPv6.
+
+
+
+
+ IP layer options - specify local/remote address, local interface
+ and local port to be used for communication with DHCP server.
+
+
+
+
+
+
+
+ Command line options
+
+ The following command line options may be used with perfdhcp tool.
+ This summary also presents its possible exit codes as well as
+ error counters printed along when test is complete:
+ $ ./perfdhcp -h
+] [-t] [-R] [-b]
+ [-n] [-p] [-d] [-D]
+ [-l] [-P] [-a]
+ [-L] [-s] [-i] [-B] [-c] [-1]
+ [-T] [-X] [-O] [-S] [-I]
+ [-x] [-w] [server]
+
+The [server] argument is the name/address of the DHCP server to
+contact. For DHCPv4 operation, exchanges are initiated by
+transmitting a DHCP DISCOVER to this address.
+
+For DHCPv6 operation, exchanges are initiated by transmitting a DHCP
+SOLICIT to this address. In the DHCPv6 case, the special name 'all'
+can be used to refer to All_DHCP_Relay_Agents_and_Servers (the
+multicast address FF02::1:2), or the special name 'servers' to refer
+to All_DHCP_Servers (the multicast address FF05::1:3). The [server]
+argument is optional only in the case that -l is used to specify an
+interface, in which case [server] defaults to 'all'.
+
+The default is to perform a single 4-way exchange, effectively pinging
+the server.
+The -r option is used to set up a performance test, without
+it exchanges are initiated as fast as possible.
+
+Options:
+-1: Take the server-ID option from the first received message.
+-4: DHCPv4 operation (default). This is incompatible with the -6 option.
+-6: DHCPv6 operation. This is incompatible with the -4 option.
+-a: When the target sending rate is not yet reached,
+ control how many exchanges are initiated before the next pause.
+-b: The base mac, duid, IP, etc, used to simulate different
+ clients. This can be specified multiple times, each instance is
+ in the = form, for instance:
+ (and default) mac=00:0c:01:02:03:04.
+-d: Specify the time after which a request is treated as
+ having been lost. The value is given in seconds and may contain a
+ fractional component. The default is 1 second.
+-E: Offset of the (DHCPv4) secs field / (DHCPv6)
+ elapsed-time option in the (second/request) template.
+ The value 0 disables it.
+-h: Print this help.
+-i: Do only the initial part of an exchange: DO or SA, depending on
+ whether -6 is given.
+-I: Offset of the (DHCPv4) IP address in the requested-IP
+ option / (DHCPv6) IA_NA option in the (second/request) template.
+-l: For DHCPv4 operation, specify the local
+ hostname/address to use when communicating with the server. By
+ default, the interface address through which traffic would
+ normally be routed to the server is used.
+ For DHCPv6 operation, specify the name of the network interface
+ via which exchanges are initiated.
+-L: Specify the local port to use
+ (the value 0 means to use the default).
+-O: Offset of the last octet to randomize in the template.
+-P: Initiate first exchanges back to back at startup.
+-r: Initiate DORA/SARR (or if -i is given, DO/SA)
+ exchanges per second. A periodic report is generated showing the
+ number of exchanges which were not completed, as well as the
+ average response latency. The program continues until
+ interrupted, at which point a final report is generated.
+-R: Specify how many different clients are used. With 1
+ (the default), all requests seem to come from the same client.
+-s: Specify the seed for randomization, making it repeatable.
+-S: Offset of the server-ID option in the
+ (second/request) template.
+-T: The name of a file containing the template to use
+ as a stream of hexadecimal digits.
+-v: Report the version number of this program.
+-w: Command to call with start/stop at the beginning/end of
+ the program.
+-x: Include extended diagnostics in the output.
+ is a string of single-keywords specifying
+ the operations for which verbose output is desired. The selector
+ keyletters are:
+ * 'a': print the decoded command line arguments
+ * 'e': print the exit reason
+ * 'i': print rate processing details
+ * 'r': print randomization details
+ * 's': print first server-id
+ * 't': when finished, print timers of all successful exchanges
+ * 'T': when finished, print templates
+-X: Transaction ID (aka. xid) offset in the template.
+
+DHCPv4 only options:
+-B: Force broadcast handling.
+
+DHCPv6 only options:
+-c: Add a rapid commit option (exchanges will be SA).
+
+The remaining options are used only in conjunction with -r:
+
+-D: Abort the test if more than requests have
+ been dropped. Use -D0 to abort if even a single request has been
+ dropped. If includes the suffix '%', it specifies a
+ maximum percentage of requests that may be dropped before abort.
+ In this case, testing of the threshold begins after 10 requests
+ have been expected to be received.
+-n: Initiate transactions. No report is
+ generated until all transactions have been initiated/waited-for,
+ after which a report is generated and the program terminates.
+-p: Send requests for the given test period, which is
+ specified in the same manner as -d. This can be used as an
+ alternative to -n, or both options can be given, in which case the
+ testing is completed when either limit is reached.
+-t: Delay in seconds between two periodic reports.
+
+Errors:
+- tooshort: received a too short message
+- orphans: received a message which doesn't match an exchange
+ (duplicate, late or not related)
+- locallimit: reached to local system limits when sending a message.
+
+Exit status:
+The exit status is:
+0 on complete success.
+1 for a general error.
+2 if an error is found in the command line arguments.
+3 if there are no general failures in operation, but one or more
+ exchanges are not successfully completed.
+]]>
+
+
+
+
+ Running a test
+
+ In order to run performance test at least two separate systems
+ have to be installed: client and server. The first one has to have
+ perfdhcp tool installed, the latter has to have DHCP server
+ running (v4 or v6). If only single system is available the client
+ and server can be run on virtual machines (running on the same
+ phisical system) but in this case performance data may be heavily
+ impacted by the performance of VMs.
+
+
+ The DHCP operates on low port numbers (67 for DHCPv4 relays and
+ 547 for DHCPv6) running perfdhcp with non-root priviliges will
+ usually result in the error message similar to this:
+ $./perfdhcp -4 -l eth3 -r 100 all
+Error running perfdhcp: Failed to bind socket 3 to 172.16.1.2/port=67
+
+ perfdhcp exposes '-L' command line option that
+ imposes use of custom local port and the following command line will
+ work:
+ $./perfdhcp -4 -l eth3 -r 100 -L 10067 all
+ but in the standard configuration no responses will be received
+ from the ISC DHCP server because server responds to default relay
+ port 67.
+
+
+ Alternative way to overcome the issue with lack of privileges
+ to use default DHCP port number is to run perfdhcp as root.
+
+
+
+ In this section the perfdhcp command line options examples
+ are presented as a quick start guide for new users. For the
+ detailed list of command line options refer to
+ .
+
+
+
+
+
+
+
+
From 32f6a8736328b1d532d4ebdcbd15b10ca1815db0 Mon Sep 17 00:00:00 2001
From: Jelte Jansen
Date: Tue, 4 Sep 2012 19:17:27 +0200
Subject: [PATCH 113/199] [2109] ZoneFinder for the improved memory datasource
Moved out the ZoneFinder-specific classes and code from memory_datasrc.[h|cc] into memory/zonefinder.[h|cc]
The new code is mostly similar to the original, but using the new data structures instead of the old. It is also no longer templated (not necessary anymore) and no longer uses the pimpl (also no longer relevant), so it should be somewhat easier to read and modify.
---
src/lib/datasrc/Makefile.am | 4 +-
src/lib/datasrc/memory/Makefile.am | 1 +
src/lib/datasrc/memory/benchmarks/Makefile.am | 3 +
src/lib/datasrc/memory/tests/Makefile.am | 3 +
src/lib/datasrc/memory/tests/run_unittests.cc | 3 +
.../memory/tests/zone_finder_unittest.cc | 972 ++++++++++++++++++
src/lib/datasrc/memory/treenode_rrset.h | 2 +
src/lib/datasrc/memory/zone_data.h | 1 +
src/lib/datasrc/memory/zone_finder.cc | 412 ++++++++
src/lib/datasrc/memory/zone_finder.h | 93 ++
src/lib/datasrc/tests/faked_nsec3.cc | 2 +
11 files changed, 1494 insertions(+), 2 deletions(-)
create mode 100644 src/lib/datasrc/memory/tests/zone_finder_unittest.cc
create mode 100644 src/lib/datasrc/memory/zone_finder.cc
create mode 100644 src/lib/datasrc/memory/zone_finder.h
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index d1e113f9c5..aa93b774ac 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = memory . tests
+SUBDIRS = . memory tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
@@ -64,7 +64,7 @@ libb10_datasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
-libb10_datasrc_la_LIBADD += memory/libdatasrc_memory.la # convenience library
+#libb10_datasrc_la_LIBADD += memory/libdatasrc_memory.la # convenience library
libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 1fb3fe7083..a2eb0d890d 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -16,4 +16,5 @@ libdatasrc_memory_la_SOURCES += treenode_rrset.h treenode_rrset.cc
libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc
libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc
libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
+libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
EXTRA_DIST = rdata_serialization_priv.cc
diff --git a/src/lib/datasrc/memory/benchmarks/Makefile.am b/src/lib/datasrc/memory/benchmarks/Makefile.am
index f4ae3eefc5..4134aa88c4 100644
--- a/src/lib/datasrc/memory/benchmarks/Makefile.am
+++ b/src/lib/datasrc/memory/benchmarks/Makefile.am
@@ -13,8 +13,11 @@ noinst_PROGRAMS = rdata_reader_bench rrset_render_bench
rdata_reader_bench_SOURCES = rdata_reader_bench.cc
rdata_reader_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la
+rdata_reader_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
rdata_reader_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
rrset_render_bench_SOURCES = rrset_render_bench.cc
rrset_render_bench_LDADD = $(top_builddir)/src/lib/datasrc/memory/libdatasrc_memory.la
+rrset_render_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+rrset_render_bench_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
rrset_render_bench_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
diff --git a/src/lib/datasrc/memory/tests/Makefile.am b/src/lib/datasrc/memory/tests/Makefile.am
index 334094d7b0..ba2fe703e6 100644
--- a/src/lib/datasrc/memory/tests/Makefile.am
+++ b/src/lib/datasrc/memory/tests/Makefile.am
@@ -24,6 +24,8 @@ run_unittests_SOURCES += domaintree_unittest.cc
run_unittests_SOURCES += treenode_rrset_unittest.cc
run_unittests_SOURCES += zone_table_unittest.cc
run_unittests_SOURCES += zone_data_unittest.cc
+run_unittests_SOURCES += zone_finder_unittest.cc
+run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
run_unittests_SOURCES += memory_segment_test.h
run_unittests_SOURCES += segment_object_holder_unittest.cc
@@ -31,6 +33,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(builddir)/../libdatasrc_memory.la
+run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
diff --git a/src/lib/datasrc/memory/tests/run_unittests.cc b/src/lib/datasrc/memory/tests/run_unittests.cc
index 998667c2cb..6321976841 100644
--- a/src/lib/datasrc/memory/tests/run_unittests.cc
+++ b/src/lib/datasrc/memory/tests/run_unittests.cc
@@ -14,10 +14,13 @@
#include
#include
+#include
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
return (isc::util::unittests::run_all());
}
diff --git a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
new file mode 100644
index 0000000000..9bd09ab231
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
@@ -0,0 +1,972 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "memory_segment_test.h"
+
+#include "../../tests/faked_nsec3.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc;
+using namespace isc::testutils;
+using boost::shared_ptr;
+using namespace isc::datasrc::test;
+using namespace isc::datasrc::memory::test;
+using namespace isc::datasrc::memory;
+
+namespace {
+// Commonly used result codes (Who should write the prefix all the time)
+using result::SUCCESS;
+using result::EXIST;
+
+// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
+// object.
+//
+// For apex (example.org)
+const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
+// For ns1.example.org
+const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+// For w.example.org
+const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+// For x.y.w.example.org (lower-cased)
+const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
+// For zzz.example.org.
+const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+
+// A simple faked NSEC3 hash calculator with a dedicated creator for it.
+//
+// This is used in some NSEC3-related tests below.
+class TestNSEC3HashCreator : public NSEC3HashCreator {
+ class TestNSEC3Hash : public NSEC3Hash {
+ private:
+ typedef map NSEC3HashMap;
+ typedef NSEC3HashMap::value_type NSEC3HashPair;
+ NSEC3HashMap map_;
+ public:
+ TestNSEC3Hash() {
+ // Build pre-defined hash
+ map_[Name("example.org")] = apex_hash;
+ map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+ map_[Name("x.y.w.example.org")] =
+ "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
+ map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+ map_[Name("w.example.org")] = w_hash;
+ map_[Name("zzz.example.org")] = zzz_hash;
+ map_[Name("smallest.example.org")] =
+ "00000000000000000000000000000000";
+ map_[Name("largest.example.org")] =
+ "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
+ }
+ virtual string calculate(const Name& name) const {
+ const NSEC3HashMap::const_iterator found = map_.find(name);
+ if (found != map_.end()) {
+ return (found->second);
+ }
+ isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
+ << name);
+ }
+ virtual bool match(const generic::NSEC3PARAM&) const {
+ return (true);
+ }
+ virtual bool match(const generic::NSEC3&) const {
+ return (true);
+ }
+ };
+
+public:
+ virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
+ return (new TestNSEC3Hash);
+ }
+ virtual NSEC3Hash* create(const generic::NSEC3&) const {
+ return (new TestNSEC3Hash);
+ }
+};
+
+
+/// \brief expensive rrset converter
+///
+/// converts any specialized rrset (which may not have implemented some
+/// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
+/// checks.
+///
+/// Done very inefficiently through text representation, speed should not
+/// be a concern here.
+ConstRRsetPtr
+convertRRset(ConstRRsetPtr src) {
+ return (textToRRset(src->toText()));
+}
+
+/// \brief Test fixture for the InMemoryZoneFinder class
+class InMemoryZoneFinderTest : public ::testing::Test {
+ // A straightforward pair of textual RR(set) and a RRsetPtr variable
+ // to store the RRset. Used to build test data below.
+ struct RRsetData {
+ const char* const text; // textual representation of an RRset
+ RRsetPtr* rrset;
+ };
+protected:
+ // The following sub tests are shared by multiple test cases, changing
+ // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
+ // expected_flags is set to either RESULT_NSEC_SIGNED or
+ // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
+ // find() is expected to set the corresponding flags.
+ // find_options should be set to FIND_DNSSEC for NSEC-signed case when
+ // NSEC is expected to be returned.
+ void findCheck(ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT,
+ ZoneFinder::FindOptions find_options =
+ ZoneFinder::FIND_DEFAULT);
+ void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT);
+ void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT,
+ ZoneFinder::FindOptions find_options =
+ ZoneFinder::FIND_DEFAULT);
+ void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT);
+ void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT);
+ void findNSECENTCheck(const Name& ent_name,
+ ConstRRsetPtr expected_nsec,
+ ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT);
+
+public:
+ InMemoryZoneFinderTest() :
+ class_(RRClass::IN()),
+ origin_("example.org"),
+ zone_data_(ZoneData::create(mem_sgmt_, origin_)),
+ zone_finder_(*zone_data_)
+ {
+ // Build test RRsets. Below, we construct an RRset for
+ // each textual RR(s) of zone_data, and assign it to the corresponding
+ // rr_xxx.
+ // Note that this contains an out-of-zone RR, and due to the
+ // validation check of masterLoad() used below, we cannot add SOA.
+ const RRsetData zone_data[] = {
+ {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
+ {"example.org. 300 IN A 192.0.2.1", &rr_a_},
+ {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
+ {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
+ {"cname.example.org. 300 IN CNAME canonical.example.org",
+ &rr_cname_},
+ {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
+ {"dname.example.org. 300 IN DNAME target.example.org.",
+ &rr_dname_},
+ {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
+ {"dname.example.org. 300 IN NS ns.dname.example.org.",
+ &rr_dname_ns_},
+ {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
+ {"child.example.org. 300 IN NS ns.child.example.org.",
+ &rr_child_ns_},
+ {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
+ &rr_child_ds_},
+ {"ns.child.example.org. 300 IN A 192.0.2.153",
+ &rr_child_glue_},
+ {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
+ &rr_grandchild_ns_},
+ {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
+ &rr_grandchild_glue_},
+ {"dname.child.example.org. 300 IN DNAME example.com.",
+ &rr_child_dname_},
+ {"example.com. 300 IN A 192.0.2.10", &rr_out_},
+ {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
+ {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
+ &rr_cnamewild_},
+ {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
+ {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
+ {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
+ &rr_nested_emptywild_},
+ {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
+ {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
+ &rr_dnamewild_},
+ {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
+ {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
+ {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
+ &rr_not_wild_another_},
+ {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
+ "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
+ &rr_nsec3_},
+ {"example.org. 300 IN NSEC wild.*.foo.example.org. "
+ "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
+ // Together with the apex NSEC, these next NSECs make a complete
+ // chain in the case of the zone for the emptyNonterminal tests
+ // (We may want to clean up this generator code and/or masterLoad
+ // so that we can prepare conflicting datasets better)
+ {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
+ "A RRSIG NSEC", &rr_ent_nsec2_},
+ {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
+ &rr_ent_nsec3_},
+ {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
+ &rr_ent_nsec4_},
+ // And these are NSECs used in different tests
+ {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
+ &rr_ns_nsec_},
+ {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
+ &rr_wild_nsec_},
+ {NULL, NULL}
+ };
+
+ for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
+ *zone_data[i].rrset = textToRRset(zone_data[i].text);
+ }
+
+ }
+
+ ~InMemoryZoneFinderTest() {
+ // Make sure we reset the hash creator to the default
+ setNSEC3HashCreator(NULL);
+ ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
+ }
+
+ // NSEC3-specific call for 'loading' data
+ void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
+ // we're only adding one anyway so this is a simplified version
+ // base nsec3 chain of rrset rdata
+ // TODO: add if already exists?
+ assert(rrset->getType() == RRType::NSEC3());
+
+ const Rdata* rdata = &rrset->getRdataIterator()->getCurrent();
+ const generic::NSEC3* nsec3_rdata = dynamic_cast(rdata);
+ NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, *nsec3_rdata);
+ // in case we happen to be replacing, destroy old
+ NSEC3Data* old_data = zone_data_->setNSEC3Data(nsec3_data);
+ if (old_data != NULL) {
+ NSEC3Data::destroy(mem_sgmt_, old_data, rrset->getClass());
+ }
+ }
+
+ // simplified version of 'loading' data
+ void addZoneData(const ConstRRsetPtr rrset) {
+ ZoneNode* node = NULL;
+
+ if (rrset->getType() == RRType::NSEC3()) {
+ return (addZoneDataNSEC3(rrset));
+ }
+ zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
+ RdataSet* next_rds = node->getData();
+
+ if (rrset->getType() == RRType::NS() &&
+ rrset->getName() != zone_data_->getOriginNode()->getName()) {
+ node->setFlag(DomainTreeNode::FLAG_CALLBACK);
+ } else if (rrset->getType() == RRType::DNAME()) {
+ node->setFlag(DomainTreeNode::FLAG_CALLBACK);
+ }
+
+ RdataSet* rdataset =
+ RdataSet::create(mem_sgmt_, encoder_, rrset, ConstRRsetPtr());
+ rdataset->next = next_rds;
+ node->setData(rdataset);
+ }
+
+ // Some data to test with
+ const RRClass class_;
+ const Name origin_;
+ // The zone finder to torture by tests
+ MemorySegmentTest mem_sgmt_;
+ memory::ZoneData* zone_data_;
+ memory::InMemoryZoneFinder zone_finder_;
+ isc::datasrc::memory::RdataEncoder encoder_;
+
+ // Placeholder for storing RRsets to be checked with rrsetsCheck()
+ vector actual_rrsets_;
+
+ /*
+ * Some RRsets to put inside the zone.
+ */
+ RRsetPtr
+ // Out of zone RRset
+ rr_out_,
+ // NS of example.org
+ rr_ns_,
+ // A of ns.example.org
+ rr_ns_a_,
+ // AAAA of ns.example.org
+ rr_ns_aaaa_,
+ // A of example.org
+ rr_a_;
+ RRsetPtr rr_cname_; // CNAME in example.org (RDATA will be added)
+ RRsetPtr rr_cname_a_; // for mixed CNAME + A case
+ RRsetPtr rr_dname_; // DNAME in example.org (RDATA will be added)
+ RRsetPtr rr_dname_a_; // for mixed DNAME + A case
+ RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
+ RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
+ RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
+ RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
+ RRsetPtr rr_child_glue_; // glue RR of the child domain
+ RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
+ RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
+ RRsetPtr rr_child_dname_; // A DNAME under NS
+ RRsetPtr rr_wild_; // Wildcard record
+ RRsetPtr rr_cnamewild_; // CNAME at a wildcard
+ RRsetPtr rr_emptywild_;
+ RRsetPtr rr_nested_emptywild_;
+ RRsetPtr rr_nswild_, rr_dnamewild_;
+ RRsetPtr rr_child_wild_;
+ RRsetPtr rr_under_wild_;
+ RRsetPtr rr_not_wild_;
+ RRsetPtr rr_not_wild_another_;
+ RRsetPtr rr_nsec3_;
+ RRsetPtr rr_nsec_;
+ RRsetPtr rr_ent_nsec2_;
+ RRsetPtr rr_ent_nsec3_;
+ RRsetPtr rr_ent_nsec4_;
+ RRsetPtr rr_ns_nsec_;
+ RRsetPtr rr_wild_nsec_;
+
+ // A faked NSEC3 hash calculator for convenience.
+ // Tests that need to use the faked hashed values should call
+ // setNSEC3HashCreator() with a pointer to this variable at the beginning
+ // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
+ TestNSEC3HashCreator nsec3_hash_creator_;
+
+ /**
+ * \brief Test one find query to the zone finder.
+ *
+ * Asks a query to the zone finder and checks it does not throw and returns
+ * expected results. It returns nothing, it just signals failures
+ * to GTEST.
+ *
+ * \param name The name to ask for.
+ * \param rrtype The RRType to ask of.
+ * \param result The expected code of the result.
+ * \param check_answer Should a check against equality of the answer be
+ * done?
+ * \param answer The expected rrset, if any should be returned.
+ * \param expected_flags The expected result flags returned via find().
+ * These can be tested using isWildcard() etc.
+ * \param zone_finder Check different InMemoryZoneFinder object than
+ * zone_finder_ (if NULL, uses zone_finder_)
+ * \param check_wild_answer Checks that the answer has the same RRs, type
+ * class and TTL as the eqxpected answer and that the name corresponds
+ * to the one searched. It is meant for checking answers for wildcard
+ * queries.
+ */
+ void findTest(const Name& name, const RRType& rrtype,
+ ZoneFinder::Result result,
+ bool check_answer = true,
+ const ConstRRsetPtr& answer = ConstRRsetPtr(),
+ ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT,
+ memory::InMemoryZoneFinder* zone_finder = NULL,
+ ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
+ bool check_wild_answer = false)
+ {
+ SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
+
+ if (zone_finder == NULL) {
+ zone_finder = &zone_finder_;
+ }
+ const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
+ RRsetPtr(); // note we use the same type as of retval of getRRsig()
+ // The whole block is inside, because we need to check the result and
+ // we can't assign to FindResult
+ EXPECT_NO_THROW({
+ ZoneFinderContextPtr find_result(zone_finder->find(
+ name, rrtype, options));
+ // Check it returns correct answers
+ EXPECT_EQ(result, find_result->code);
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+ find_result->isWildcard());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
+ != 0, find_result->isNSECSigned());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
+ != 0, find_result->isNSEC3Signed());
+ if (check_answer) {
+ if (!answer) {
+ ASSERT_FALSE(find_result->rrset);
+ } else {
+ ASSERT_TRUE(find_result->rrset);
+ rrsetCheck(answer, convertRRset(find_result->rrset));
+ if (answer_sig) {
+ ASSERT_TRUE(find_result->rrset->getRRsig());
+ rrsetCheck(answer_sig,
+ find_result->rrset->getRRsig());
+ }
+ }
+ } else if (check_wild_answer) {
+ ASSERT_NE(ConstRRsetPtr(), answer) <<
+ "Wrong test, don't check for wild names if you expect "
+ "empty answer";
+ ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
+ "No answer found";
+ // Build the expected answer using the given name and
+ // other parameter of the base wildcard RRset.
+ RRsetPtr wildanswer(new RRset(name, answer->getClass(),
+ answer->getType(),
+ answer->getTTL()));
+ RdataIteratorPtr expectedIt(answer->getRdataIterator());
+ for (; !expectedIt->isLast(); expectedIt->next()) {
+ wildanswer->addRdata(expectedIt->getCurrent());
+ }
+ rrsetCheck(wildanswer, find_result->rrset);
+
+ // Same for the RRSIG, if any.
+ if (answer_sig) {
+ ASSERT_TRUE(find_result->rrset->getRRsig());
+
+ RRsetPtr wildsig(new RRset(name,
+ answer_sig->getClass(),
+ RRType::RRSIG(),
+ answer_sig->getTTL()));
+ RdataIteratorPtr expectedIt(
+ answer_sig->getRdataIterator());
+ for (; !expectedIt->isLast(); expectedIt->next()) {
+ wildsig->addRdata(expectedIt->getCurrent());
+ }
+ rrsetCheck(wildsig, find_result->rrset->getRRsig());
+ }
+ }
+ });
+ }
+ /**
+ * \brief Calls the findAll on the finder and checks the result.
+ */
+ void findAllTest(const Name& name, ZoneFinder::Result result,
+ const vector& expected_rrsets,
+ ZoneFinder::FindResultFlags expected_flags =
+ ZoneFinder::RESULT_DEFAULT,
+ memory::InMemoryZoneFinder* finder = NULL,
+ const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
+ ZoneFinder::FindOptions options =
+ ZoneFinder::FIND_DEFAULT)
+ {
+ if (finder == NULL) {
+ finder = &zone_finder_;
+ }
+ std::vector target;
+ ZoneFinderContextPtr find_result(finder->findAll(name, target,
+ options));
+ EXPECT_EQ(result, find_result->code);
+ if (!rrset_result) {
+ EXPECT_FALSE(find_result->rrset);
+ } else {
+ ASSERT_TRUE(find_result->rrset);
+ rrsetCheck(rrset_result, convertRRset(find_result->rrset));
+ }
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+ find_result->isWildcard());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
+ != 0, find_result->isNSECSigned());
+ EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
+ != 0, find_result->isNSEC3Signed());
+ // Convert all rrsets to 'full' ones before checking
+ std::vector converted_rrsets;
+ BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
+ converted_rrsets.push_back(convertRRset(cur_rrset));
+ }
+ rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
+ converted_rrsets.begin(), converted_rrsets.end());
+ }
+};
+
+/**
+ * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
+ *
+ * Takes the created zone finder and checks its properties they are the same
+ * as passed parameters.
+ */
+TEST_F(InMemoryZoneFinderTest, constructor) {
+ ASSERT_EQ(origin_, zone_finder_.getOrigin());
+}
+
+TEST_F(InMemoryZoneFinderTest, findCNAME) {
+ // install CNAME RR
+ addZoneData(rr_cname_);
+
+ // Find A RR of the same. Should match the CNAME
+ findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
+ rr_cname_);
+
+ // Find the CNAME itself. Should result in normal SUCCESS
+ findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
+ rr_cname_);
+}
+
+TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
+ // There's nothing special when we find a CNAME under a zone cut
+ // (with FIND_GLUE_OK). The behavior is different from BIND 9,
+ // so we test this case explicitly.
+ addZoneData(rr_child_ns_);
+ ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
+ "cname.child.example.org. 300 IN CNAME target.child.example.org.");
+ addZoneData(rr_cname_under_cut_);
+ findTest(Name("cname.child.example.org"), RRType::AAAA(),
+ ZoneFinder::CNAME, true, rr_cname_under_cut_,
+ ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+// Search under a DNAME record. It should return the DNAME
+TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
+ EXPECT_NO_THROW(addZoneData(rr_dname_));
+ findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
+ true, rr_dname_);
+}
+
+// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
+// influences only the data below (see RFC 2672, section 3)
+TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
+ EXPECT_NO_THROW(addZoneData(rr_dname_));
+ EXPECT_NO_THROW(addZoneData(rr_dname_a_));
+
+ const Name dname_name(rr_dname_->getName());
+ findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
+ findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
+ rr_dname_);
+ findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
+}
+
+// Try searching something that is both under NS and DNAME, without and with
+// GLUE_OK mode (it should stop at the NS and DNAME respectively).
+TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
+ addZoneData(rr_child_ns_);
+ addZoneData(rr_child_dname_);
+
+ Name lowName("below.dname.child.example.org.");
+
+ findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
+ findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
+ ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+// Test adding child zones and zone cut handling
+TEST_F(InMemoryZoneFinderTest, delegationNS) {
+ // add in-zone data
+ EXPECT_NO_THROW(addZoneData(rr_ns_));
+
+ // install a zone cut
+ EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+
+ // below the zone cut
+ findTest(Name("www.child.example.org"), RRType::A(),
+ ZoneFinder::DELEGATION, true, rr_child_ns_);
+
+ // at the zone cut
+ findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
+ true, rr_child_ns_);
+ findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
+ true, rr_child_ns_);
+
+ // finding NS for the apex (origin) node. This must not be confused
+ // with delegation due to the existence of an NS RR.
+ findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
+
+ // unusual case of "nested delegation": the highest cut should be used.
+ EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+ findTest(Name("www.grand.child.example.org"), RRType::A(),
+ // note: !rr_grandchild_ns_
+ ZoneFinder::DELEGATION, true, rr_child_ns_);
+}
+
+TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
+ // Similar setup to the previous one, but with DS RR at the delegation
+ // point.
+ addZoneData(rr_ns_);
+ addZoneData(rr_child_ns_);
+ addZoneData(rr_child_ds_);
+
+ // Normal types of query should result in delegation, but DS query
+ // should be considered in-zone (but only exactly at the delegation point).
+ findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
+ true, rr_child_ns_);
+ findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
+ true, rr_child_ds_);
+ findTest(Name("grand.child.example.org"), RRType::DS(),
+ ZoneFinder::DELEGATION, true, rr_child_ns_);
+
+ // There's nothing special for DS query at the zone apex. It would
+ // normally result in NXRRSET.
+ findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
+ true, ConstRRsetPtr());
+}
+
+TEST_F(InMemoryZoneFinderTest, findAny) {
+ EXPECT_NO_THROW(addZoneData(rr_a_));
+ EXPECT_NO_THROW(addZoneData(rr_ns_));
+ EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+
+ vector expected_sets;
+
+ // origin
+ expected_sets.push_back(rr_a_);
+ expected_sets.push_back(rr_ns_);
+ findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
+
+ // out zone name
+ EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
+ vector()),
+ OutOfZone);
+
+ expected_sets.clear();
+ expected_sets.push_back(rr_child_glue_);
+ findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
+
+ // add zone cut
+ EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+
+ // zone cut
+ findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
+ vector(), ZoneFinder::RESULT_DEFAULT,
+ NULL, rr_child_ns_);
+
+ // glue for this zone cut
+ findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
+ vector(), ZoneFinder::RESULT_DEFAULT,
+ NULL, rr_child_ns_);
+}
+
+TEST_F(InMemoryZoneFinderTest, glue) {
+ // install zone data:
+ // a zone cut
+ EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+ // glue for this cut
+ EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+ // a nested zone cut (unusual)
+ EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+ // glue under the deeper zone cut
+ EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
+
+ // by default glue is hidden due to the zone cut
+ findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
+ true, rr_child_ns_);
+
+
+ // If we do it in the "glue OK" mode, we should find the exact match.
+ findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+ rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
+ ZoneFinder::FIND_GLUE_OK);
+
+ // glue OK + NXRRSET case
+ findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
+ true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
+ ZoneFinder::FIND_GLUE_OK);
+
+ // glue OK + NXDOMAIN case
+ findTest(Name("www.child.example.org"), RRType::A(),
+ ZoneFinder::DELEGATION, true, rr_child_ns_,
+ ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+
+ // nested cut case. The glue should be found.
+ findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
+ ZoneFinder::SUCCESS,
+ true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
+ ZoneFinder::FIND_GLUE_OK);
+
+ // A non-existent name in nested cut. This should result in delegation
+ // at the highest zone cut.
+ findTest(Name("www.grand.child.example.org"), RRType::TXT(),
+ ZoneFinder::DELEGATION, true, rr_child_ns_,
+ ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+/**
+ * \brief Test searching.
+ *
+ * Check it finds or does not find correctly and does not throw exceptions.
+ * \todo This doesn't do any kind of CNAME and so on. If it isn't
+ * directly there, it just tells it doesn't exist.
+ */
+void
+InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
+ ZoneFinder::FindOptions find_options)
+{
+ // Fill some data inside
+ // Now put all the data we have there. It should throw nothing
+ EXPECT_NO_THROW(addZoneData(rr_ns_));
+ EXPECT_NO_THROW(addZoneData(rr_ns_a_));
+ EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
+ EXPECT_NO_THROW(addZoneData(rr_a_));
+ if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+ addZoneData(rr_nsec3_);
+ zone_data_->setSigned(true);
+ }
+ if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ addZoneData(rr_nsec_);
+ zone_data_->setSigned(true);
+ }
+
+ // These two should be successful
+ findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
+ findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+ rr_ns_a_);
+
+ // These domains don't exist. (and one is out of the zone). In an
+ // NSEC-signed zone with DNSSEC records requested, it should return the
+ // covering NSEC for the query name (the actual NSEC in the test data may
+ // not really "cover" it, but for the purpose of this test it's okay).
+ ConstRRsetPtr expected_nsec; // by default it's NULL
+ if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
+ (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
+ expected_nsec = rr_nsec_;
+ }
+
+ // There's no other name between this one and the origin, so when NSEC
+ // is to be returned it should be the origin NSEC.
+ findTest(Name("nothere.example.org"), RRType::A(),
+ ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+ NULL, find_options);
+
+ // The previous name in the zone is "ns.example.org", but it doesn't
+ // have an NSEC. It should be skipped and the origin NSEC will be
+ // returned as the "closest NSEC".
+ findTest(Name("nxdomain.example.org"), RRType::A(),
+ ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+ NULL, find_options);
+ EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
+ OutOfZone);
+
+ // These domain exist but don't have the provided RRType. For the latter
+ // one we now add its NSEC (which was delayed so that it wouldn't break
+ // other cases above).
+ findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
+ expected_nsec, expected_flags, NULL, find_options);
+
+ if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ addZoneData(rr_ns_nsec_);
+ if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
+ expected_nsec = rr_ns_nsec_;
+ }
+ }
+ findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
+ expected_nsec, expected_flags, NULL, find_options);
+}
+
+TEST_F(InMemoryZoneFinderTest, find) {
+ findCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
+ findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
+ // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
+ // anything (the NSEC3_SIGNED flag is always set, and no records are
+ // returned for negative cases regardless).
+ findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
+ // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
+ findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+// Generalized test for Empty Nonterminal (ENT) cases with NSEC
+void
+InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
+ ConstRRsetPtr expected_nsec,
+ ZoneFinder::FindResultFlags expected_flags)
+{
+ addZoneData(rr_emptywild_);
+ addZoneData(rr_under_wild_);
+
+ // Sanity check: Should result in NXRRSET
+ findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+ ConstRRsetPtr(), expected_flags);
+ // Sanity check: No NSEC added yet
+ findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+ ConstRRsetPtr(), expected_flags,
+ NULL, ZoneFinder::FIND_DNSSEC);
+
+ // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
+ // there are no sigs)
+ addZoneData(rr_nsec_);
+ addZoneData(rr_ent_nsec2_);
+ addZoneData(rr_ent_nsec3_);
+ addZoneData(rr_ent_nsec4_);
+ zone_data_->setSigned(true);
+
+ // Should result in NXRRSET, and RESULT_NSEC_SIGNED
+ findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+ ConstRRsetPtr(),
+ expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
+
+ // And check for the NSEC if DNSSEC_OK
+ findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+ expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
+ NULL, ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
+ // Non-wildcard case
+ findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
+}
+
+TEST_F(InMemoryZoneFinderTest, DISABLED_findNSECEmptyNonterminalWildcard) {
+ // Wildcard case, above actual wildcard
+ findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
+}
+
+TEST_F(InMemoryZoneFinderTest,DISABLED_findNSECEmptyNonterminalAtWildcard) {
+ // Wildcard case, at actual wildcard
+ findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
+ ZoneFinder::RESULT_WILDCARD);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
+ // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
+ findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
+}
+
+void
+InMemoryZoneFinderTest::emptyNodeCheck(
+ ZoneFinder::FindResultFlags expected_flags)
+{
+ /*
+ * The backend RBTree for this test should look like as follows:
+ * example.org
+ * |
+ * baz (empty; easy case)
+ * / | \
+ * bar | x.foo ('foo' part is empty; a bit trickier)
+ * bbb
+ * /
+ * aaa
+ */
+
+ // Construct the test zone
+ const char* const names[] = {
+ "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
+ "bbb.baz.example.org.", NULL};
+ for (int i = 0; names[i] != NULL; ++i) {
+ ConstRRsetPtr rrset = textToRRset(string(names[i]) +
+ " 300 IN A 192.0.2.1");
+ addZoneData(rrset);
+ }
+ if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+ addZoneData(rr_nsec3_);
+ zone_data_->setSigned(true);
+ }
+ if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+ addZoneData(rr_nsec_);
+ zone_data_->setSigned(true);
+ }
+
+ // empty node matching, easy case: the node for 'baz' exists with
+ // no data.
+ findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
+ ConstRRsetPtr(), expected_flags);
+
+ // empty node matching, a trickier case: the node for 'foo' is part of
+ // "x.foo", which should be considered an empty node.
+ findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
+ ConstRRsetPtr(), expected_flags);
+
+ // "org" is contained in "example.org", but it shouldn't be treated as
+ // NXRRSET because it's out of zone.
+ // Note: basically we don't expect such a query to be performed (the common
+ // operation is to identify the best matching zone first then perform
+ // search it), but we shouldn't be confused even in the unexpected case.
+ EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNode) {
+ emptyNodeCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
+ emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
+ emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+// DISABLED: nsec3 will be re-added in #2118
+TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3) {
+ // Set up the faked hash calculator.
+ setNSEC3HashCreator(&nsec3_hash_creator_);
+
+ // Add a few NSEC3 records:
+ // apex (example.org.): hash=0P..
+ // ns1.example.org: hash=2T..
+ // w.example.org: hash=01..
+ // zzz.example.org: hash=R5..
+ const string apex_nsec3_text = string(apex_hash) + ".example.org." +
+ string(nsec3_common);
+ addZoneData(textToRRset(apex_nsec3_text));
+ const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+ string(nsec3_common);
+ addZoneData(textToRRset(ns1_nsec3_text));
+ const string w_nsec3_text = string(w_hash) + ".example.org." +
+ string(nsec3_common);
+ addZoneData(textToRRset(w_nsec3_text));
+ const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+ string(nsec3_common);
+ addZoneData(textToRRset(zzz_nsec3_text));
+
+ performNSEC3Test(zone_finder_);
+}
+
+// DISABLED: NSEC3 will be re-added in #2218
+TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3ForBadZone) {
+ // Set up the faked hash calculator.
+ setNSEC3HashCreator(&nsec3_hash_creator_);
+
+ // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
+ // findNSEC3() should be rejected.
+ EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+ DataSourceError);
+
+ // Only having NSEC3PARAM isn't enough
+ addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
+ "1 0 12 aabbccdd"));
+ EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+ DataSourceError);
+
+ // Unless NSEC3 for apex is added the result in the recursive mode
+ // is guaranteed.
+ const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+ string(nsec3_common);
+ addZoneData(textToRRset(ns1_nsec3_text));
+ EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+ DataSourceError);
+}
+
+}
diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h
index 2ad3a3c289..1da4d52aaa 100644
--- a/src/lib/datasrc/memory/treenode_rrset.h
+++ b/src/lib/datasrc/memory/treenode_rrset.h
@@ -252,6 +252,8 @@ private:
const dns::Name* const realname_;
};
+typedef boost::shared_ptr TreeNodeRRsetPtr;
+
} // namespace memory
} // namespace datasrc
} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data.h b/src/lib/datasrc/memory/zone_data.h
index f59268033f..b0cef47db6 100644
--- a/src/lib/datasrc/memory/zone_data.h
+++ b/src/lib/datasrc/memory/zone_data.h
@@ -43,6 +43,7 @@ namespace memory {
typedef DomainTree ZoneTree;
typedef DomainTreeNode ZoneNode;
+typedef DomainTreeNodeChain ZoneNodeChain;
/// \brief NSEC3 data for a DNS zone.
///
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
new file mode 100644
index 0000000000..a058f35b0c
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -0,0 +1,412 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+using namespace isc::dns;
+using namespace isc::datasrc::memory;
+using namespace isc::datasrc;
+
+namespace {
+
+// (temporary?) convenience function to create a treenoderrset
+// given an rdataset; we should probably have some pool so these
+// do not need to be allocated dynamically
+// For now they are still dynamically allocated, and have a fixed rrclass (...)
+TreeNodeRRsetPtr
+createTreeNodeRRset(const ZoneNode* node,
+ const RdataSet* rdataset)
+{
+ return TreeNodeRRsetPtr(new TreeNodeRRset(RRClass::IN(), node,
+ rdataset, true));
+}
+
+struct FindState {
+ FindState(bool glue_ok) :
+ zonecut_node_(NULL),
+ dname_node_(NULL),
+ rrset_(TreeNodeRRsetPtr()),
+ glue_ok_(glue_ok)
+ {}
+
+ // These will be set to a domain node of the highest delegation point,
+ // if any. In fact, we could use a single variable instead of both.
+ // But then we would need to distinquish these two cases by something
+ // else and it seemed little more confusing when this was written.
+ const ZoneNode* zonecut_node_;
+ const ZoneNode* dname_node_;
+
+ // Delegation RRset (NS or DNAME), if found.
+ TreeNodeRRsetPtr rrset_;
+
+ // Whether to continue search below a delegation point.
+ // Set at construction time.
+ const bool glue_ok_;
+};
+
+// A callback called from possible zone cut nodes and nodes with DNAME.
+// This will be passed from findNode() to \c RBTree::find().
+bool cutCallback(const ZoneNode& node, FindState* state) {
+ // We need to look for DNAME first, there's allowed case where
+ // DNAME and NS coexist in the apex. DNAME is the one to notice,
+ // the NS is authoritative, not delegation (corner case explicitly
+ // allowed by section 3 of 2672)
+ const RdataSet* found_dname = RdataSet::find(node.getData(), RRType::DNAME());
+
+ if (found_dname != NULL) {
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
+ state->dname_node_ = &node;
+ state->rrset_ = createTreeNodeRRset(&node, found_dname);
+ return (true);
+ }
+
+ // Look for NS
+ const RdataSet* found_ns = RdataSet::find(node.getData(), RRType::NS());
+ if (found_ns != NULL) {
+ // We perform callback check only for the highest zone cut in the
+ // rare case of nested zone cuts.
+ if (state->zonecut_node_ != NULL) {
+ return (false);
+ }
+
+ LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
+
+ // BIND 9 checks if this node is not the origin. That's probably
+ // because it can support multiple versions for dynamic updates
+ // and IXFR, and it's possible that the callback is called at
+ // the apex and the DNAME doesn't exist for a particular version.
+ // It cannot happen for us (at least for now), so we don't do
+ // that check.
+ state->zonecut_node_ = &node;
+ state->rrset_ = createTreeNodeRRset(&node, found_ns);
+
+ // Unless glue is allowed the search stops here, so we return
+ // false; otherwise return true to continue the search.
+ return (!state->glue_ok_);
+ }
+
+ // This case should not happen because we enable callback only
+ // when we add an RR searched for above.
+ assert(0);
+ // This is here to avoid warning (therefore compilation error)
+ // in case assert is turned off. Otherwise we could get "Control
+ // reached end of non-void function".
+ return (false);
+}
+
+} // unnamed namespace
+
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+namespace {
+ // convenience function to fill in the final details
+ isc::datasrc::memory::ZoneFinderResultContext
+ createFindResult(const ZoneData& zone_data,
+ ZoneFinder::Result code,
+ TreeNodeRRsetPtr rrset,
+ const ZoneNode* node,
+ bool wild = false) {
+ ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
+
+ if (wild) {
+ flags = flags | ZoneFinder::RESULT_WILDCARD;
+ }
+ if (code == ZoneFinder::NXRRSET || code == ZoneFinder::NXDOMAIN || wild) {
+ if (zone_data.isNSEC3Signed()) {
+ flags = flags | ZoneFinder::RESULT_NSEC3_SIGNED;
+ } else if (zone_data.isSigned()) {
+ flags = flags | ZoneFinder::RESULT_NSEC_SIGNED;
+ }
+ }
+
+ return (ZoneFinderResultContext(code, rrset, flags, node));
+ }
+} // end anonymous namespace
+
+class InMemoryZoneFinder::Context : public ZoneFinder::Context {
+public:
+ /// \brief Constructor.
+ ///
+ /// Note that we don't have a specific constructor for the findAll() case.
+ /// For (successful) type ANY query, found_node points to the
+ /// corresponding RB node, which is recorded within this specialized
+ /// context.
+ Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
+ ZoneFinderResultContext result) :
+ ZoneFinder::Context(finder, options,
+ ResultContext(result.code, result.rrset,
+ result.flags)),
+ rrset_(result.rrset), found_node_(result.found_node)
+ {}
+
+private:
+ const TreeNodeRRsetPtr rrset_;
+ const ZoneNode* const found_node_;
+};
+
+boost::shared_ptr
+InMemoryZoneFinder::find(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ const FindOptions options)
+{
+ // call find_internal, and wrap the result in a ContextPtr
+ return ZoneFinderContextPtr(new Context(*this, options,
+ find_internal(name,
+ type,
+ NULL,
+ options)));
+}
+
+boost::shared_ptr
+InMemoryZoneFinder::findAll(const isc::dns::Name& name,
+ std::vector& target,
+ const FindOptions options)
+{
+ // call find_internal, and wrap the result in a ContextPtr
+ return ZoneFinderContextPtr(new Context(*this, options,
+ find_internal(name,
+ RRType::ANY(),
+ &target,
+ options)));
+}
+
+namespace {
+
+TreeNodeRRsetPtr
+getClosestNSEC(const ZoneData& zone_data,
+ ZoneNodeChain& chain,
+ ZoneFinder::FindOptions options)
+{
+ if (!zone_data.isSigned() || (options & ZoneFinder::FIND_DNSSEC) == 0 || zone_data.isNSEC3Signed()) {
+ return (TreeNodeRRsetPtr());
+ }
+
+ const ZoneNode* prev_node;
+ while ((prev_node = zone_data.getZoneTree().previousNode(chain)) != NULL) {
+ if (!prev_node->isEmpty()) {
+ const RdataSet* found = RdataSet::find(prev_node->getData(), RRType::NSEC());
+ if (found != NULL) {
+ return (createTreeNodeRRset(prev_node, found));
+ }
+ }
+ }
+ // This must be impossible and should be an internal bug.
+ // See the description at the method declaration.
+ assert(false);
+ // Even though there is an assert here, strict compilers
+ // will still need some return value.
+ return (TreeNodeRRsetPtr());
+}
+
+// A helper function for the NXRRSET case in find(). If the zone is
+// NSEC-signed and DNSSEC records are requested, try to find NSEC
+// on the given node, and return it if found; return NULL for all other
+// cases.
+TreeNodeRRsetPtr
+getNSECForNXRRSET(const ZoneData& zone_data,
+ ZoneFinder::FindOptions options,
+ const ZoneNode* node)
+{
+ if (zone_data.isSigned() &&
+ !zone_data.isNSEC3Signed() &&
+ (options & ZoneFinder::FIND_DNSSEC) != 0) {
+ const RdataSet* found = RdataSet::find(node->getData(), RRType::NSEC());
+ if (found != NULL) {
+ return (createTreeNodeRRset(node, found));
+ }
+ }
+ return (TreeNodeRRsetPtr());
+}
+
+
+class FindNodeResult {
+public:
+ // Bitwise flags to represent supplemental information of the
+ // search result:
+ // Search resulted in a wildcard match.
+ static const unsigned int FIND_WILDCARD = 1;
+ // Search encountered a zone cut due to NS but continued to look for
+ // a glue.
+ static const unsigned int FIND_ZONECUT = 2;
+
+ FindNodeResult(ZoneFinder::Result code_param,
+ ZoneNode* node_param,
+ TreeNodeRRsetPtr rrset_param,
+ unsigned int flags_param = 0) :
+ code(code_param),
+ node(node_param),
+ rrset(rrset_param),
+ flags(flags_param)
+ {}
+ const ZoneFinder::Result code;
+ const ZoneNode* node;
+ TreeNodeRRsetPtr rrset;
+ const unsigned int flags;
+};
+
+FindNodeResult findNode(const ZoneData& zone_data,
+ const Name& name,
+ ZoneNodeChain& chain,
+ ZoneFinder::FindOptions options)
+{
+ ZoneNode* node = NULL;
+ FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
+
+ const ZoneTree& tree(zone_data.getZoneTree());
+ ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
+ &node, chain, cutCallback, &state);
+ const unsigned int zonecut_flag =
+ (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
+ if (result == ZoneTree::EXACTMATCH) {
+ return (FindNodeResult(ZoneFinder::SUCCESS, node, state.rrset_,
+ zonecut_flag));
+ } else if (result == ZoneTree::PARTIALMATCH) {
+ assert(node != NULL);
+ if (state.dname_node_ != NULL) { // DNAME
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+ arg(state.rrset_->getName());
+ return (FindNodeResult(ZoneFinder::DNAME, NULL, state.rrset_));
+ }
+ if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+ arg(state.rrset_->getName());
+ return (FindNodeResult(ZoneFinder::DELEGATION, NULL, state.rrset_));
+ }
+ if (chain.getLastComparisonResult().getRelation() ==
+ NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
+ return (FindNodeResult(ZoneFinder::NXRRSET, node,
+ getClosestNSEC(zone_data, chain, options)));
+ }
+ // TODO: wildcard (see memory_datasrc.cc:480)
+ // Nothing really matched.
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
+ return (FindNodeResult(ZoneFinder::NXDOMAIN, node,
+ getClosestNSEC(zone_data, chain, options)));
+ } else {
+ // If the name is neither an exact or partial match, it is
+ // out of bailiwick, which is considered an error.
+ isc_throw(OutOfZone, name.toText() << " not in " <<
+ zone_data.getOriginNode()->getName());
+ }
+}
+
+} // end anonymous namespace
+
+ZoneFinderResultContext
+InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ std::vector* target,
+ const FindOptions options)
+{
+ // Get the node. All other cases than an exact match are handled
+ // in findNode(). We simply construct a result structure and return.
+ ZoneNodeChain chain;
+ const FindNodeResult node_result =
+ findNode(zone_data_, name, chain, options);
+ if (node_result.code != SUCCESS) {
+ return (createFindResult(zone_data_, node_result.code, node_result.rrset, NULL));
+ }
+
+ const ZoneNode* node = node_result.node;
+ assert(node != NULL);
+
+ // We've found an exact match, may or may not be a result of wildcard.
+ // TODO, ticket #2110
+ // If there is an exact match but the node is empty, it's equivalent
+ // to NXRRSET.
+ if (node->isEmpty()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
+ arg(name);
+ return (createFindResult(zone_data_, NXRRSET,
+ getClosestNSEC(zone_data_, chain, options),
+ node));
+ }
+
+ const RdataSet* found;
+
+ // If the node callback is enabled, this may be a zone cut. If it
+ // has a NS RR, we should return a delegation, but not in the apex.
+ // There is one exception: the case for DS query, which should always
+ // be considered in-zone lookup.
+ if (node->getFlag(ZoneNode::FLAG_CALLBACK) &&
+ node != zone_data_.getOriginNode() && type != RRType::DS()) {
+ found = RdataSet::find(node->getData(), RRType::NS());
+ if (found != NULL) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEM_EXACT_DELEGATION).arg(name);
+ // TODO: rename argument (wildcards, see #2110)
+ return (createFindResult(zone_data_, DELEGATION, createTreeNodeRRset(node, found), node));
+ }
+ }
+
+ // Handle type any query
+ if (target != NULL && node->getData() != NULL) {
+ // Empty domain will be handled as NXRRSET by normal processing
+ const RdataSet* cur_rds = node->getData();
+ while (cur_rds != NULL) {
+ target->push_back(createTreeNodeRRset(node, cur_rds));
+ cur_rds = cur_rds->getNext();
+ }
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
+ arg(name);
+ return (createFindResult(zone_data_, SUCCESS, TreeNodeRRsetPtr(), node));
+ }
+
+ const RdataSet* currds = node->getData();
+ while (currds != NULL) {
+ currds = currds->getNext();
+ }
+ found = RdataSet::find(node->getData(), type);
+ if (found != NULL) {
+ // Good, it is here
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
+ arg(type);
+ return (createFindResult(zone_data_, SUCCESS, createTreeNodeRRset(node, found), node));
+ } else {
+ // Next, try CNAME.
+ found = RdataSet::find(node->getData(), RRType::CNAME());
+ if (found != NULL) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
+ return (createFindResult(zone_data_, CNAME, createTreeNodeRRset(node, found), node));
+ }
+ }
+ // No exact match or CNAME. Get NSEC if necessary and return NXRRSET.
+ return (createFindResult(zone_data_, NXRRSET, getNSECForNXRRSET(zone_data_, options, node), node));
+}
+
+isc::datasrc::ZoneFinder::FindNSEC3Result
+InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
+ (void)name;
+ (void)recursive;
+ isc_throw(isc::NotImplemented, "not completed yet! please implement me");
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
new file mode 100644
index 0000000000..37a3a23311
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -0,0 +1,93 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_MEMORY_ZONE_FINDER_H
+#define DATASRC_MEMORY_ZONE_FINDER_H 1
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+class ZoneFinderResultContext {
+public:
+ /// \brief Constructor
+ ///
+ /// The first three parameters correspond to those of
+ /// ZoneFinder::ResultContext. If node is non NULL, it specifies the
+ /// found RBNode in the search.
+ ZoneFinderResultContext(ZoneFinder::Result code_param,
+ TreeNodeRRsetPtr rrset_param,
+ ZoneFinder::FindResultFlags flags_param,
+ const ZoneNode* node) :
+ code(code_param), rrset(rrset_param), flags(flags_param),
+ found_node(node)
+ {}
+
+ const ZoneFinder::Result code;
+ const TreeNodeRRsetPtr rrset;
+ const ZoneFinder::FindResultFlags flags;
+ const ZoneNode* const found_node;
+};
+
+class InMemoryZoneFinder : boost::noncopyable, public ZoneFinder {
+public:
+ InMemoryZoneFinder(const ZoneData& zone_data) : zone_data_(zone_data) {}
+
+ virtual boost::shared_ptr find(
+ const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ const FindOptions options = FIND_DEFAULT);
+
+ virtual boost::shared_ptr findAll(
+ const isc::dns::Name& name,
+ std::vector& target,
+ const FindOptions options = FIND_DEFAULT);
+
+ virtual FindNSEC3Result
+ findNSEC3(const isc::dns::Name& name, bool recursive);
+
+ virtual isc::dns::Name getOrigin() const {
+ return zone_data_.getOriginNode()->getName();
+ }
+
+ virtual isc::dns::RRClass getClass() const {
+ isc_throw(isc::NotImplemented, "this method is not relevant and should "
+ "probably be removed from the API");
+ }
+
+ class Context;
+
+private:
+ ZoneFinderResultContext find_internal(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ std::vector* target,
+ const FindOptions options =
+ FIND_DEFAULT);
+
+ const ZoneData& zone_data_;
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_ZONE_FINDER_H
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
index b702d288ba..1e499976e4 100644
--- a/src/lib/datasrc/tests/faked_nsec3.cc
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -156,6 +156,7 @@ performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist) {
finder.findNSEC3(origin, false));
}
+/*
// Recursive mode doesn't change the result in this case.
{
SCOPED_TRACE("apex, recursive mode");
@@ -211,6 +212,7 @@ performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist) {
zzz_nsec3_text, "",
finder.findNSEC3(largest_name, false));
}
+*/
}
}
From 6db917d5a6a1f209bf6381779b6673b0a64fd909 Mon Sep 17 00:00:00 2001
From: Jelte Jansen
Date: Fri, 7 Sep 2012 11:09:56 +0200
Subject: [PATCH 114/199] [2109] refactor creation of TreeNodeRRsets
and make RRClass a construction-time argument
---
.../memory/tests/zone_finder_unittest.cc | 2 +-
src/lib/datasrc/memory/zone_finder.cc | 343 +++++++++---------
src/lib/datasrc/memory/zone_finder.h | 3 +-
3 files changed, 177 insertions(+), 171 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
index 9bd09ab231..98d1118f38 100644
--- a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
+++ b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
@@ -182,7 +182,7 @@ public:
class_(RRClass::IN()),
origin_("example.org"),
zone_data_(ZoneData::create(mem_sgmt_, origin_)),
- zone_finder_(*zone_data_)
+ zone_finder_(*zone_data_, class_)
{
// Build test RRsets. Below, we construct an RRset for
// each textual RR(s) of zone_data, and assign it to the corresponding
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index a058f35b0c..f46415ad53 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -29,25 +29,33 @@ using namespace isc::dns;
using namespace isc::datasrc::memory;
using namespace isc::datasrc;
-namespace {
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace {
// (temporary?) convenience function to create a treenoderrset
// given an rdataset; we should probably have some pool so these
// do not need to be allocated dynamically
// For now they are still dynamically allocated, and have a fixed rrclass (...)
TreeNodeRRsetPtr
createTreeNodeRRset(const ZoneNode* node,
- const RdataSet* rdataset)
+ const RdataSet* rdataset,
+ const RRClass& rrclass)
{
- return TreeNodeRRsetPtr(new TreeNodeRRset(RRClass::IN(), node,
- rdataset, true));
+ if (rdataset != NULL) {
+ return TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node,
+ rdataset, true));
+ } else {
+ return TreeNodeRRsetPtr();
+ }
}
struct FindState {
FindState(bool glue_ok) :
zonecut_node_(NULL),
dname_node_(NULL),
- rrset_(TreeNodeRRsetPtr()),
+ rrset_(NULL),
glue_ok_(glue_ok)
{}
@@ -59,7 +67,8 @@ struct FindState {
const ZoneNode* dname_node_;
// Delegation RRset (NS or DNAME), if found.
- TreeNodeRRsetPtr rrset_;
+ //TreeNodeRRsetPtr rrset_;
+ const RdataSet* rrset_;
// Whether to continue search below a delegation point.
// Set at construction time.
@@ -78,7 +87,7 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
if (found_dname != NULL) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
state->dname_node_ = &node;
- state->rrset_ = createTreeNodeRRset(&node, found_dname);
+ state->rrset_ = found_dname;
return (true);
}
@@ -100,7 +109,7 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
// It cannot happen for us (at least for now), so we don't do
// that check.
state->zonecut_node_ = &node;
- state->rrset_ = createTreeNodeRRset(&node, found_ns);
+ state->rrset_ = found_ns;
// Unless glue is allowed the search stops here, so we return
// false; otherwise return true to continue the search.
@@ -116,36 +125,153 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
return (false);
}
-} // unnamed namespace
+// convenience function to fill in the final details
+isc::datasrc::memory::ZoneFinderResultContext
+createFindResult(const RRClass& rrclass,
+ const ZoneData& zone_data,
+ ZoneFinder::Result code,
+ const RdataSet* rrset,
+ const ZoneNode* node,
+ bool wild = false) {
+ ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-namespace {
- // convenience function to fill in the final details
- isc::datasrc::memory::ZoneFinderResultContext
- createFindResult(const ZoneData& zone_data,
- ZoneFinder::Result code,
- TreeNodeRRsetPtr rrset,
- const ZoneNode* node,
- bool wild = false) {
- ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
-
- if (wild) {
- flags = flags | ZoneFinder::RESULT_WILDCARD;
+ if (wild) {
+ flags = flags | ZoneFinder::RESULT_WILDCARD;
+ }
+ if (code == ZoneFinder::NXRRSET || code == ZoneFinder::NXDOMAIN || wild) {
+ if (zone_data.isNSEC3Signed()) {
+ flags = flags | ZoneFinder::RESULT_NSEC3_SIGNED;
+ } else if (zone_data.isSigned()) {
+ flags = flags | ZoneFinder::RESULT_NSEC_SIGNED;
}
- if (code == ZoneFinder::NXRRSET || code == ZoneFinder::NXDOMAIN || wild) {
- if (zone_data.isNSEC3Signed()) {
- flags = flags | ZoneFinder::RESULT_NSEC3_SIGNED;
- } else if (zone_data.isSigned()) {
- flags = flags | ZoneFinder::RESULT_NSEC_SIGNED;
+ }
+
+ return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rrset, rrclass), flags, node));
+}
+
+const RdataSet*
+getClosestNSEC(const ZoneData& zone_data,
+ ZoneNodeChain& chain,
+ const ZoneNode** nsec_node,
+ ZoneFinder::FindOptions options)
+{
+ if (!zone_data.isSigned() || (options & ZoneFinder::FIND_DNSSEC) == 0 || zone_data.isNSEC3Signed()) {
+ return (NULL);
+ }
+
+ const ZoneNode* prev_node;
+ while ((prev_node = zone_data.getZoneTree().previousNode(chain)) != NULL) {
+ if (!prev_node->isEmpty()) {
+ const RdataSet* found = RdataSet::find(prev_node->getData(), RRType::NSEC());
+ if (found != NULL) {
+ *nsec_node = prev_node;
+ return (found);
}
}
-
- return (ZoneFinderResultContext(code, rrset, flags, node));
}
+ // This must be impossible and should be an internal bug.
+ // See the description at the method declaration.
+ assert(false);
+ // Even though there is an assert here, strict compilers
+ // will still need some return value.
+ return (NULL);
+}
+
+// A helper function for the NXRRSET case in find(). If the zone is
+// NSEC-signed and DNSSEC records are requested, try to find NSEC
+// on the given node, and return it if found; return NULL for all other
+// cases.
+const RdataSet*
+getNSECForNXRRSET(const ZoneData& zone_data,
+ ZoneFinder::FindOptions options,
+ const ZoneNode* node)
+{
+ if (zone_data.isSigned() &&
+ !zone_data.isNSEC3Signed() &&
+ (options & ZoneFinder::FIND_DNSSEC) != 0) {
+ const RdataSet* found = RdataSet::find(node->getData(), RRType::NSEC());
+ if (found != NULL) {
+ return (found);
+ }
+ }
+ return (NULL);
+}
+
+
+class FindNodeResult {
+public:
+ // Bitwise flags to represent supplemental information of the
+ // search result:
+ // Search resulted in a wildcard match.
+ static const unsigned int FIND_WILDCARD = 1;
+ // Search encountered a zone cut due to NS but continued to look for
+ // a glue.
+ static const unsigned int FIND_ZONECUT = 2;
+
+ FindNodeResult(ZoneFinder::Result code_param,
+ const ZoneNode* node_param,
+ const RdataSet* rrset_param,
+ unsigned int flags_param = 0) :
+ code(code_param),
+ node(node_param),
+ rrset(rrset_param),
+ flags(flags_param)
+ {}
+ const ZoneFinder::Result code;
+ const ZoneNode* node;
+ const RdataSet* rrset;
+ const unsigned int flags;
+};
+
+FindNodeResult findNode(const ZoneData& zone_data,
+ const Name& name,
+ ZoneNodeChain& chain,
+ ZoneFinder::FindOptions options)
+{
+ ZoneNode* node = NULL;
+ FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
+
+ const ZoneTree& tree(zone_data.getZoneTree());
+ ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
+ &node, chain, cutCallback, &state);
+ const unsigned int zonecut_flag =
+ (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
+ if (result == ZoneTree::EXACTMATCH) {
+ return (FindNodeResult(ZoneFinder::SUCCESS, node, state.rrset_,
+ zonecut_flag));
+ } else if (result == ZoneTree::PARTIALMATCH) {
+ assert(node != NULL);
+ if (state.dname_node_ != NULL) { // DNAME
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
+ arg(state.dname_node_->getName());
+ return (FindNodeResult(ZoneFinder::DNAME, state.dname_node_, state.rrset_));
+ }
+ if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
+ arg(state.zonecut_node_->getName());
+ return (FindNodeResult(ZoneFinder::DELEGATION, state.zonecut_node_, state.rrset_));
+ }
+ if (chain.getLastComparisonResult().getRelation() ==
+ NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
+ const ZoneNode* nsec_node;
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data, chain, &nsec_node, options);
+ return (FindNodeResult(ZoneFinder::NXRRSET, nsec_node, nsec_rds));
+ }
+ // TODO: wildcard (see memory_datasrc.cc:480)
+ // Nothing really matched.
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
+ const ZoneNode* nsec_node;
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data, chain, &nsec_node, options);
+ return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
+ } else {
+ // If the name is neither an exact or partial match, it is
+ // out of bailiwick, which is considered an error.
+ isc_throw(OutOfZone, name.toText() << " not in " <<
+ zone_data.getOriginNode()->getName());
+ }
+}
+
} // end anonymous namespace
class InMemoryZoneFinder::Context : public ZoneFinder::Context {
@@ -195,129 +321,6 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
options)));
}
-namespace {
-
-TreeNodeRRsetPtr
-getClosestNSEC(const ZoneData& zone_data,
- ZoneNodeChain& chain,
- ZoneFinder::FindOptions options)
-{
- if (!zone_data.isSigned() || (options & ZoneFinder::FIND_DNSSEC) == 0 || zone_data.isNSEC3Signed()) {
- return (TreeNodeRRsetPtr());
- }
-
- const ZoneNode* prev_node;
- while ((prev_node = zone_data.getZoneTree().previousNode(chain)) != NULL) {
- if (!prev_node->isEmpty()) {
- const RdataSet* found = RdataSet::find(prev_node->getData(), RRType::NSEC());
- if (found != NULL) {
- return (createTreeNodeRRset(prev_node, found));
- }
- }
- }
- // This must be impossible and should be an internal bug.
- // See the description at the method declaration.
- assert(false);
- // Even though there is an assert here, strict compilers
- // will still need some return value.
- return (TreeNodeRRsetPtr());
-}
-
-// A helper function for the NXRRSET case in find(). If the zone is
-// NSEC-signed and DNSSEC records are requested, try to find NSEC
-// on the given node, and return it if found; return NULL for all other
-// cases.
-TreeNodeRRsetPtr
-getNSECForNXRRSET(const ZoneData& zone_data,
- ZoneFinder::FindOptions options,
- const ZoneNode* node)
-{
- if (zone_data.isSigned() &&
- !zone_data.isNSEC3Signed() &&
- (options & ZoneFinder::FIND_DNSSEC) != 0) {
- const RdataSet* found = RdataSet::find(node->getData(), RRType::NSEC());
- if (found != NULL) {
- return (createTreeNodeRRset(node, found));
- }
- }
- return (TreeNodeRRsetPtr());
-}
-
-
-class FindNodeResult {
-public:
- // Bitwise flags to represent supplemental information of the
- // search result:
- // Search resulted in a wildcard match.
- static const unsigned int FIND_WILDCARD = 1;
- // Search encountered a zone cut due to NS but continued to look for
- // a glue.
- static const unsigned int FIND_ZONECUT = 2;
-
- FindNodeResult(ZoneFinder::Result code_param,
- ZoneNode* node_param,
- TreeNodeRRsetPtr rrset_param,
- unsigned int flags_param = 0) :
- code(code_param),
- node(node_param),
- rrset(rrset_param),
- flags(flags_param)
- {}
- const ZoneFinder::Result code;
- const ZoneNode* node;
- TreeNodeRRsetPtr rrset;
- const unsigned int flags;
-};
-
-FindNodeResult findNode(const ZoneData& zone_data,
- const Name& name,
- ZoneNodeChain& chain,
- ZoneFinder::FindOptions options)
-{
- ZoneNode* node = NULL;
- FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
-
- const ZoneTree& tree(zone_data.getZoneTree());
- ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
- &node, chain, cutCallback, &state);
- const unsigned int zonecut_flag =
- (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
- if (result == ZoneTree::EXACTMATCH) {
- return (FindNodeResult(ZoneFinder::SUCCESS, node, state.rrset_,
- zonecut_flag));
- } else if (result == ZoneTree::PARTIALMATCH) {
- assert(node != NULL);
- if (state.dname_node_ != NULL) { // DNAME
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
- arg(state.rrset_->getName());
- return (FindNodeResult(ZoneFinder::DNAME, NULL, state.rrset_));
- }
- if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
- arg(state.rrset_->getName());
- return (FindNodeResult(ZoneFinder::DELEGATION, NULL, state.rrset_));
- }
- if (chain.getLastComparisonResult().getRelation() ==
- NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
- return (FindNodeResult(ZoneFinder::NXRRSET, node,
- getClosestNSEC(zone_data, chain, options)));
- }
- // TODO: wildcard (see memory_datasrc.cc:480)
- // Nothing really matched.
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
- return (FindNodeResult(ZoneFinder::NXDOMAIN, node,
- getClosestNSEC(zone_data, chain, options)));
- } else {
- // If the name is neither an exact or partial match, it is
- // out of bailiwick, which is considered an error.
- isc_throw(OutOfZone, name.toText() << " not in " <<
- zone_data.getOriginNode()->getName());
- }
-}
-
-} // end anonymous namespace
-
ZoneFinderResultContext
InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
const isc::dns::RRType& type,
@@ -330,7 +333,7 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
const FindNodeResult node_result =
findNode(zone_data_, name, chain, options);
if (node_result.code != SUCCESS) {
- return (createFindResult(zone_data_, node_result.code, node_result.rrset, NULL));
+ return (createFindResult(rrclass_, zone_data_, node_result.code, node_result.rrset, node_result.node));
}
const ZoneNode* node = node_result.node;
@@ -343,9 +346,11 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
if (node->isEmpty()) {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
arg(name);
- return (createFindResult(zone_data_, NXRRSET,
- getClosestNSEC(zone_data_, chain, options),
- node));
+ const ZoneNode* nsec_node;
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data_, chain, &nsec_node, options);
+ return (createFindResult(rrclass_, zone_data_, NXRRSET,
+ nsec_rds,
+ nsec_node));
}
const RdataSet* found;
@@ -361,7 +366,7 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEM_EXACT_DELEGATION).arg(name);
// TODO: rename argument (wildcards, see #2110)
- return (createFindResult(zone_data_, DELEGATION, createTreeNodeRRset(node, found), node));
+ return (createFindResult(rrclass_, zone_data_, DELEGATION, found, node));
}
}
@@ -370,12 +375,12 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
// Empty domain will be handled as NXRRSET by normal processing
const RdataSet* cur_rds = node->getData();
while (cur_rds != NULL) {
- target->push_back(createTreeNodeRRset(node, cur_rds));
+ target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_));
cur_rds = cur_rds->getNext();
}
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
arg(name);
- return (createFindResult(zone_data_, SUCCESS, TreeNodeRRsetPtr(), node));
+ return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node));
}
const RdataSet* currds = node->getData();
@@ -387,17 +392,17 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
// Good, it is here
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
arg(type);
- return (createFindResult(zone_data_, SUCCESS, createTreeNodeRRset(node, found), node));
+ return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node));
} else {
// Next, try CNAME.
found = RdataSet::find(node->getData(), RRType::CNAME());
if (found != NULL) {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
- return (createFindResult(zone_data_, CNAME, createTreeNodeRRset(node, found), node));
+ return (createFindResult(rrclass_, zone_data_, CNAME, found, node));
}
}
// No exact match or CNAME. Get NSEC if necessary and return NXRRSET.
- return (createFindResult(zone_data_, NXRRSET, getNSECForNXRRSET(zone_data_, options, node), node));
+ return (createFindResult(rrclass_, zone_data_, NXRRSET, getNSECForNXRRSET(zone_data_, options, node), node));
}
isc::datasrc::ZoneFinder::FindNSEC3Result
@@ -407,6 +412,6 @@ InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
isc_throw(isc::NotImplemented, "not completed yet! please implement me");
}
-}
-}
-}
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
index 37a3a23311..f80ab1f99d 100644
--- a/src/lib/datasrc/memory/zone_finder.h
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -50,7 +50,7 @@ public:
class InMemoryZoneFinder : boost::noncopyable, public ZoneFinder {
public:
- InMemoryZoneFinder(const ZoneData& zone_data) : zone_data_(zone_data) {}
+ InMemoryZoneFinder(const ZoneData& zone_data, const isc::dns::RRClass& rrclass) : zone_data_(zone_data), rrclass_(rrclass) {}
virtual boost::shared_ptr find(
const isc::dns::Name& name,
@@ -84,6 +84,7 @@ private:
FIND_DEFAULT);
const ZoneData& zone_data_;
+ const isc::dns::RRClass& rrclass_;
};
} // namespace memory
From 6b7f1283d0de285cff60ecc25b6901715a6f104c Mon Sep 17 00:00:00 2001
From: Jelte Jansen
Date: Fri, 7 Sep 2012 15:26:18 +0200
Subject: [PATCH 115/199] [2109] clean up for new in-memory ZoneFinder
layout, documentation, etc.
---
.../memory/tests/zone_finder_unittest.cc | 38 +---
src/lib/datasrc/memory/zone_finder.cc | 184 +++++++++++++++---
src/lib/datasrc/memory/zone_finder.h | 52 ++++-
3 files changed, 202 insertions(+), 72 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
index 98d1118f38..15fec597d8 100644
--- a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
+++ b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
@@ -13,40 +13,17 @@
// PERFORMANCE OF THIS SOFTWARE.
#include "memory_segment_test.h"
-
#include "../../tests/faked_nsec3.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
#include
-#include
-
#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-
#include
#include
+#include
+
+#include
+
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
@@ -266,14 +243,13 @@ public:
}
// NSEC3-specific call for 'loading' data
+ // This needs to be updated and checked when implementing #2118
void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
- // we're only adding one anyway so this is a simplified version
- // base nsec3 chain of rrset rdata
- // TODO: add if already exists?
assert(rrset->getType() == RRType::NSEC3());
const Rdata* rdata = &rrset->getRdataIterator()->getCurrent();
- const generic::NSEC3* nsec3_rdata = dynamic_cast(rdata);
+ const generic::NSEC3* nsec3_rdata =
+ dynamic_cast(rdata);
NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, *nsec3_rdata);
// in case we happen to be replacing, destroy old
NSEC3Data* old_data = zone_data_->setNSEC3Data(nsec3_data);
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index f46415ad53..994b0f98f3 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -34,16 +34,23 @@ namespace datasrc {
namespace memory {
namespace {
-// (temporary?) convenience function to create a treenoderrset
-// given an rdataset; we should probably have some pool so these
-// do not need to be allocated dynamically
-// For now they are still dynamically allocated, and have a fixed rrclass (...)
+/// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
+/// the given RRClass
+///
+/// We should probably have some pool so these do not need to be allocated
+/// dynamically.
+///
+/// \param node The ZoneNode found by the find() calls
+/// \param rdataset The RdataSet to create the RRsetPtr for
+/// \param rrclass The RRClass as passed by the client
+///
+/// Returns an empty TreeNodeRRsetPtr is either node or rdataset is NULL.
TreeNodeRRsetPtr
createTreeNodeRRset(const ZoneNode* node,
const RdataSet* rdataset,
const RRClass& rrclass)
{
- if (rdataset != NULL) {
+ if (node != NULL && rdataset != NULL) {
return TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node,
rdataset, true));
} else {
@@ -51,6 +58,11 @@ createTreeNodeRRset(const ZoneNode* node,
}
}
+/// Maintain intermediate data specific to the search context used in
+/// \c find().
+///
+/// It will be passed to \c cutCallback() (see below) and record a possible
+/// zone cut node and related RRset (normally NS or DNAME).
struct FindState {
FindState(bool glue_ok) :
zonecut_node_(NULL),
@@ -67,7 +79,6 @@ struct FindState {
const ZoneNode* dname_node_;
// Delegation RRset (NS or DNAME), if found.
- //TreeNodeRRsetPtr rrset_;
const RdataSet* rrset_;
// Whether to continue search below a delegation point.
@@ -82,7 +93,8 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
// DNAME and NS coexist in the apex. DNAME is the one to notice,
// the NS is authoritative, not delegation (corner case explicitly
// allowed by section 3 of 2672)
- const RdataSet* found_dname = RdataSet::find(node.getData(), RRType::DNAME());
+ const RdataSet* found_dname = RdataSet::find(node.getData(),
+ RRType::DNAME());
if (found_dname != NULL) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
@@ -126,6 +138,15 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
}
// convenience function to fill in the final details
+//
+// Set up ZoneFinderResultContext object as a return value of find(),
+// taking into account wildcard matches and DNSSEC information. We set
+// the NSEC/NSEC3 flag when applicable regardless of the find option; the
+// caller would simply ignore these when they didn't request DNSSEC
+// related results.
+//
+// Also performs the conversion of node + RdataSet into a TreeNodeRRsetPtr
+//
isc::datasrc::memory::ZoneFinderResultContext
createFindResult(const RRClass& rrclass,
const ZoneData& zone_data,
@@ -146,23 +167,49 @@ createFindResult(const RRClass& rrclass,
}
}
- return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rrset, rrclass), flags, node));
+ return (ZoneFinderResultContext(code, createTreeNodeRRset(node,
+ rrset,
+ rrclass),
+ flags, node));
}
+// A helper function for NSEC-signed zones. It searches the zone for
+// the "closest" NSEC corresponding to the search context stored in
+// node_path (it should contain sufficient information to identify the
+// previous name of the query name in the zone). In some cases the
+// immediate closest name may not have NSEC (when it's under a zone cut
+// for glue records, or even when the zone is partly broken), so this
+// method continues the search until it finds a name that has NSEC,
+// and returns the one found first. Due to the prerequisite (see below),
+// it should always succeed.
+//
+// node_path must store valid search context (in practice, it's expected
+// to be set by findNode()); otherwise the underlying RBTree implementation
+// throws.
+//
+// If the zone is not considered NSEC-signed or DNSSEC records were not
+// required in the original search context (specified in options), this
+// method doesn't bother to find NSEC, and simply returns NULL. So, by
+// definition of "NSEC-signed", when it really tries to find an NSEC it
+// should succeed; there should be one at least at the zone origin.
const RdataSet*
getClosestNSEC(const ZoneData& zone_data,
- ZoneNodeChain& chain,
+ ZoneNodeChain& node_path,
const ZoneNode** nsec_node,
ZoneFinder::FindOptions options)
{
- if (!zone_data.isSigned() || (options & ZoneFinder::FIND_DNSSEC) == 0 || zone_data.isNSEC3Signed()) {
+ if (!zone_data.isSigned() ||
+ (options & ZoneFinder::FIND_DNSSEC) == 0 ||
+ zone_data.isNSEC3Signed()) {
return (NULL);
}
const ZoneNode* prev_node;
- while ((prev_node = zone_data.getZoneTree().previousNode(chain)) != NULL) {
+ while ((prev_node = zone_data.getZoneTree().previousNode(node_path))
+ != NULL) {
if (!prev_node->isEmpty()) {
- const RdataSet* found = RdataSet::find(prev_node->getData(), RRType::NSEC());
+ const RdataSet* found =
+ RdataSet::find(prev_node->getData(), RRType::NSEC());
if (found != NULL) {
*nsec_node = prev_node;
return (found);
@@ -189,7 +236,8 @@ getNSECForNXRRSET(const ZoneData& zone_data,
if (zone_data.isSigned() &&
!zone_data.isNSEC3Signed() &&
(options & ZoneFinder::FIND_DNSSEC) != 0) {
- const RdataSet* found = RdataSet::find(node->getData(), RRType::NSEC());
+ const RdataSet* found = RdataSet::find(node->getData(),
+ RRType::NSEC());
if (found != NULL) {
return (found);
}
@@ -197,7 +245,7 @@ getNSECForNXRRSET(const ZoneData& zone_data,
return (NULL);
}
-
+// Structure to hold result data of the findNode() call
class FindNodeResult {
public:
// Bitwise flags to represent supplemental information of the
@@ -223,9 +271,67 @@ public:
const unsigned int flags;
};
+// Implementation notes: this method identifies an ZoneNode that best matches
+// the give name in terms of DNS query handling. In many cases,
+// DomainTree::find() will result in EXACTMATCH or PARTIALMATCH (note that
+// the given name is generally expected to be contained in the zone, so
+// even if it doesn't exist, it should at least match the zone origin).
+// If it finds an exact match, that's obviously the best one. The partial
+// match case is more complicated.
+//
+// We first need to consider the case where search hits a delegation point,
+// either due to NS or DNAME. They are indicated as either dname_node_ or
+// zonecut_node_ being non NULL. Usually at most one of them will be
+// something else than NULL (it might happen both are NULL, in which case we
+// consider it NOT FOUND). There's one corner case when both might be
+// something else than NULL and it is in case there's a DNAME under a zone
+// cut and we search in glue OK mode ‒ in that case we don't stop on the
+// domain with NS and ignore it for the answer, but it gets set anyway. Then
+// we find the DNAME and we need to act by it, therefore we first check for
+// DNAME and then for NS. In all other cases it doesn't matter, as at least
+// one of them is NULL.
+//
+// Next, we need to check if the ZoneTree search stopped at a node for a
+// subdomain of the search name (so the comparison result that stopped the
+// search is "SUPERDOMAIN"), it means the stopping node is an empty
+// non-terminal node. In this case the search name is considered to exist
+// but no data should be found there.
+//
+// (TODO: check this part when doing #2110)
+// If none of above is the case, we then consider whether there's a matching
+// wildcard. DomainTree::find() records the node if it encounters a
+// "wildcarding" node, i.e., the immediate ancestor of a wildcard name
+// (e.g., wild.example.com for *.wild.example.com), and returns it if it
+// doesn't find any node that better matches the query name. In this case
+// we'll check if there's indeed a wildcard below the wildcarding node.
+//
+// Note, first, that the wildcard is checked after the empty
+// non-terminal domain case above, because if that one triggers, it
+// means we should not match according to 4.3.3 of RFC 1034 (the query
+// name is known to exist).
+//
+// Before we try to find a wildcard, we should check whether there's
+// an existing node that would cancel the wildcard match. If
+// DomainTree::find() stopped at a node which has a common ancestor
+// with the query name, it might mean we are comparing with a
+// non-wildcard node. In that case, we check which part is common. If
+// we have something in common that lives below the node we got (the
+// one above *), then we should cancel the match according to section
+// 4.3.3 of RFC 1034 (as the name between the wildcard domain and the
+// query name is known to exist).
+//
+// If there's no node below the wildcarding node that shares a common ancestor
+// of the query name, we can conclude the wildcard is the best match.
+// We'll then identify the wildcard node via an incremental search. Note that
+// there's no possibility that the query name is at an empty non terminal
+// node below the wildcarding node at this stage; that case should have been
+// caught above.
+//
+// If none of the above succeeds, we conclude the name doesn't exist in
+// the zone, and throw an OutOfZone exception.
FindNodeResult findNode(const ZoneData& zone_data,
const Name& name,
- ZoneNodeChain& chain,
+ ZoneNodeChain& node_path,
ZoneFinder::FindOptions options)
{
ZoneNode* node = NULL;
@@ -233,7 +339,8 @@ FindNodeResult findNode(const ZoneData& zone_data,
const ZoneTree& tree(zone_data.getZoneTree());
ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
- &node, chain, cutCallback, &state);
+ &node, node_path, cutCallback,
+ &state);
const unsigned int zonecut_flag =
(state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
if (result == ZoneTree::EXACTMATCH) {
@@ -244,25 +351,34 @@ FindNodeResult findNode(const ZoneData& zone_data,
if (state.dname_node_ != NULL) { // DNAME
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
arg(state.dname_node_->getName());
- return (FindNodeResult(ZoneFinder::DNAME, state.dname_node_, state.rrset_));
+ return (FindNodeResult(ZoneFinder::DNAME, state.dname_node_,
+ state.rrset_));
}
if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
arg(state.zonecut_node_->getName());
- return (FindNodeResult(ZoneFinder::DELEGATION, state.zonecut_node_, state.rrset_));
+ return (FindNodeResult(ZoneFinder::DELEGATION,
+ state.zonecut_node_,
+ state.rrset_));
}
- if (chain.getLastComparisonResult().getRelation() ==
+ if (node_path.getLastComparisonResult().getRelation() ==
NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUPER_STOP).arg(name);
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEM_SUPER_STOP).arg(name);
const ZoneNode* nsec_node;
- const RdataSet* nsec_rds = getClosestNSEC(zone_data, chain, &nsec_node, options);
- return (FindNodeResult(ZoneFinder::NXRRSET, nsec_node, nsec_rds));
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data,
+ node_path,
+ &nsec_node,
+ options);
+ return (FindNodeResult(ZoneFinder::NXRRSET, nsec_node,
+ nsec_rds));
}
- // TODO: wildcard (see memory_datasrc.cc:480)
+ // TODO: wildcard (see memory_datasrc.cc:480 and ticket #2110)
// Nothing really matched.
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
const ZoneNode* nsec_node;
- const RdataSet* nsec_rds = getClosestNSEC(zone_data, chain, &nsec_node, options);
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
+ &nsec_node, options);
return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
} else {
// If the name is neither an exact or partial match, it is
@@ -274,6 +390,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
} // end anonymous namespace
+// Specialization of the ZoneFinder::Context for the in-memory finder.
class InMemoryZoneFinder::Context : public ZoneFinder::Context {
public:
/// \brief Constructor.
@@ -300,7 +417,6 @@ InMemoryZoneFinder::find(const isc::dns::Name& name,
const isc::dns::RRType& type,
const FindOptions options)
{
- // call find_internal, and wrap the result in a ContextPtr
return ZoneFinderContextPtr(new Context(*this, options,
find_internal(name,
type,
@@ -313,7 +429,6 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
std::vector& target,
const FindOptions options)
{
- // call find_internal, and wrap the result in a ContextPtr
return ZoneFinderContextPtr(new Context(*this, options,
find_internal(name,
RRType::ANY(),
@@ -329,11 +444,12 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
{
// Get the node. All other cases than an exact match are handled
// in findNode(). We simply construct a result structure and return.
- ZoneNodeChain chain;
+ ZoneNodeChain node_path;
const FindNodeResult node_result =
- findNode(zone_data_, name, chain, options);
+ findNode(zone_data_, name, node_path, options);
if (node_result.code != SUCCESS) {
- return (createFindResult(rrclass_, zone_data_, node_result.code, node_result.rrset, node_result.node));
+ return (createFindResult(rrclass_, zone_data_, node_result.code,
+ node_result.rrset, node_result.node));
}
const ZoneNode* node = node_result.node;
@@ -347,7 +463,8 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
arg(name);
const ZoneNode* nsec_node;
- const RdataSet* nsec_rds = getClosestNSEC(zone_data_, chain, &nsec_node, options);
+ const RdataSet* nsec_rds = getClosestNSEC(zone_data_, node_path,
+ &nsec_node, options);
return (createFindResult(rrclass_, zone_data_, NXRRSET,
nsec_rds,
nsec_node));
@@ -366,7 +483,8 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEM_EXACT_DELEGATION).arg(name);
// TODO: rename argument (wildcards, see #2110)
- return (createFindResult(rrclass_, zone_data_, DELEGATION, found, node));
+ return (createFindResult(rrclass_, zone_data_, DELEGATION,
+ found, node));
}
}
@@ -402,7 +520,9 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
}
}
// No exact match or CNAME. Get NSEC if necessary and return NXRRSET.
- return (createFindResult(rrclass_, zone_data_, NXRRSET, getNSECForNXRRSET(zone_data_, options, node), node));
+ return (createFindResult(rrclass_, zone_data_, NXRRSET,
+ getNSECForNXRRSET(zone_data_, options, node),
+ node));
}
isc::datasrc::ZoneFinder::FindNSEC3Result
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
index f80ab1f99d..8f2c687028 100644
--- a/src/lib/datasrc/memory/zone_finder.h
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -48,40 +48,74 @@ public:
const ZoneNode* const found_node;
};
+/// A derived zone finder class intended to be used with the memory data
+/// source, using ZoneData for its contents.
class InMemoryZoneFinder : boost::noncopyable, public ZoneFinder {
public:
- InMemoryZoneFinder(const ZoneData& zone_data, const isc::dns::RRClass& rrclass) : zone_data_(zone_data), rrclass_(rrclass) {}
+ /// \brief Constructor.
+ ///
+ /// Since ZoneData does not keep RRClass information, but this
+ /// information is needed in order to construct actual RRsets,
+ /// this needs to be passed here (the datasource client should
+ /// have this information). In the future, this may be replaced
+ /// by some construction to pull TreeNodeRRsets from a pool, but
+ /// currently, these are created dynamically with the given RRclass
+ ///
+ /// \param zone_data The ZoneData containing the zone.
+ /// \param rrclass The RR class of the zone
+ InMemoryZoneFinder(const ZoneData& zone_data,
+ const isc::dns::RRClass& rrclass) :
+ zone_data_(zone_data),
+ rrclass_(rrclass)
+ {}
+ /// \brief Find an RRset in the datasource
virtual boost::shared_ptr find(
const isc::dns::Name& name,
const isc::dns::RRType& type,
const FindOptions options = FIND_DEFAULT);
+ /// \brief Version of find that returns all types at once
+ ///
+ /// It acts the same as find, just that when the correct node is found,
+ /// all the RRsets are filled into the target parameter instead of being
+ /// returned by the result.
virtual boost::shared_ptr findAll(
const isc::dns::Name& name,
std::vector& target,
const FindOptions options = FIND_DEFAULT);
+ /// Look for NSEC3 for proving (non)existence of given name.
+ ///
+ /// See documentation in \c Zone.
virtual FindNSEC3Result
findNSEC3(const isc::dns::Name& name, bool recursive);
+ /// \brief Returns the origin of the zone.
virtual isc::dns::Name getOrigin() const {
return zone_data_.getOriginNode()->getName();
}
+ /// \brief Returns the RR class of the zone.
virtual isc::dns::RRClass getClass() const {
- isc_throw(isc::NotImplemented, "this method is not relevant and should "
- "probably be removed from the API");
+ return rrclass_;
}
- class Context;
private:
- ZoneFinderResultContext find_internal(const isc::dns::Name& name,
- const isc::dns::RRType& type,
- std::vector* target,
- const FindOptions options =
- FIND_DEFAULT);
+ /// \brief In-memory version of finder context.
+ ///
+ /// The implementation (and any specialized interface) is completely local
+ /// to the InMemoryZoneFinder class, so it's defined as private
+ class Context;
+
+ /// Actual implementation for both find() and findAll()
+ ZoneFinderResultContext find_internal(
+ const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ std::vector* target,
+ const FindOptions options =
+ FIND_DEFAULT);
const ZoneData& zone_data_;
const isc::dns::RRClass& rrclass_;
From 1982543450f925e2f6b3b0a029b6c9425788854e Mon Sep 17 00:00:00 2001
From: Jelte Jansen
Date: Fri, 7 Sep 2012 16:38:03 +0200
Subject: [PATCH 116/199] [2109] uncomment some dead code
that got committed by accident and should not have been disabled
---
src/lib/datasrc/tests/faked_nsec3.cc | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
index 1e499976e4..b702d288ba 100644
--- a/src/lib/datasrc/tests/faked_nsec3.cc
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -156,7 +156,6 @@ performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist) {
finder.findNSEC3(origin, false));
}
-/*
// Recursive mode doesn't change the result in this case.
{
SCOPED_TRACE("apex, recursive mode");
@@ -212,7 +211,6 @@ performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist) {
zzz_nsec3_text, "",
finder.findNSEC3(largest_name, false));
}
-*/
}
}
From ed1a5d91d8ca0826a6c6370abfa511c052b60c24 Mon Sep 17 00:00:00 2001
From: Jelte Jansen
Date: Fri, 7 Sep 2012 17:20:28 +0200
Subject: [PATCH 117/199] [2151] add well-known static wildcard labelsequence
---
src/lib/dns/labelsequence.h | 15 +++++++++++++++
src/lib/dns/tests/labelsequence_unittest.cc | 6 ++++++
2 files changed, 21 insertions(+)
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
index 545ce12133..b9105506c1 100644
--- a/src/lib/dns/labelsequence.h
+++ b/src/lib/dns/labelsequence.h
@@ -53,6 +53,14 @@ public:
static const size_t MAX_SERIALIZED_LENGTH =
Name::MAX_WIRE + Name::MAX_LABELS + 1;
+ ///
+ /// \name Well-known LabelSequence constants
+ ///
+ //@{
+ /// Wildcard label ("*")
+ static const LabelSequence& WILDCARD_LABEL();
+ //@}
+
/// \brief Constructs a LabelSequence for the given name
///
/// \note The associated Name MUST remain in scope during the lifetime
@@ -410,6 +418,13 @@ private:
std::ostream&
operator<<(std::ostream& os, const LabelSequence& label_sequence);
+inline const LabelSequence&
+LabelSequence::WILDCARD_LABEL() {
+ static const uint8_t wildcard_buf[4] = { 0x01, 0x00, 0x01, '*' };
+ static const LabelSequence wild_ls(wildcard_buf);
+ return (wild_ls);
+}
+
} // end namespace dns
} // end namespace isc
diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc
index 28f624aabd..06092c008e 100644
--- a/src/lib/dns/tests/labelsequence_unittest.cc
+++ b/src/lib/dns/tests/labelsequence_unittest.cc
@@ -1174,4 +1174,10 @@ TEST_F(ExtendableLabelSequenceTest, extendBadData) {
check_equal(full_ls2, els);
}
+// Check the static fixed 'wildcard' LabelSequence
+TEST(WildCardLabelSequence, wildcard) {
+ ASSERT_FALSE(LabelSequence::WILDCARD_LABEL().isAbsolute());
+ ASSERT_EQ("*", LabelSequence::WILDCARD_LABEL().toText());
+}
+
}
From 5a70502ad2679d135e26db9f3eb0a523eefd83e6 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 06:44:25 +0530
Subject: [PATCH 118/199] [2108] Add tests for out of zone names
---
.../memory/tests/memory_client_unittest.cc | 23 +++++++++++++++++++
.../datasrc/memory/tests/testdata/Makefile.am | 1 +
.../testdata/example.org-out-of-zone.zone | 5 ++++
3 files changed, 29 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index fb9d339a84..18dacab4db 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -281,6 +281,15 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
+ // Out of zone names should throw.
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-out-of-zone.zone"),
+ MasterLoadError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
@@ -389,6 +398,20 @@ TEST_F(MemoryClientTest, addRRsetToNonExistentZoneThrows) {
EXPECT_THROW(client_->add(Name("example.org"), rrset_a), DataSourceError);
}
+TEST_F(MemoryClientTest, addOutOfZoneThrows) {
+ // Out of zone names should throw.
+ client_->load(Name("example.org"),
+ TEST_DATA_DIR "/example.org-empty.zone");
+
+ RRsetPtr rrset_a(new RRset(Name("a.example.com"),
+ RRClass::IN(), RRType::A(), RRTTL(300)));
+ rrset_a->addRdata(rdata::in::A("192.0.2.1"));
+
+ EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
+ OutOfZone);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, addNullRRsetThrows) {
client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-rrsigs.zone");
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index d52397261b..50d68b3598 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -17,3 +17,4 @@ EXTRA_DIST += example.org-multiple-nsec3.zone
EXTRA_DIST += example.org-multiple-nsec3param.zone
EXTRA_DIST += example.org-nsec3-signed.zone
EXTRA_DIST += example.org-nsec3-signed-no-param.zone
+EXTRA_DIST += example.org-out-of-zone.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone b/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone
new file mode 100644
index 0000000000..e3afb74bb4
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone
@@ -0,0 +1,5 @@
+;; test zone file used for ZoneFinderContext tests.
+;; RRSIGs are (obviouslly) faked ones for testing.
+
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 75 3600 300 3600000 3600
+a.example.com. 3600 IN A 192.168.0.1
From 86d8c6421097faeb05a2abc1638c61c44913bd27 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 07:00:20 +0530
Subject: [PATCH 119/199] [2108] Check that loading a zone with wildcard NS
names throws an exception
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 9 +++++++++
src/lib/datasrc/memory/tests/testdata/Makefile.am | 1 +
.../memory/tests/testdata/example.org-wildcard-ns.zone | 4 ++++
3 files changed, 14 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 18dacab4db..69bf5baf48 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -290,6 +290,15 @@ TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadWildcardNSThrows) {
+ // Wildcard NS names should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-wildcard-ns.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 50d68b3598..a674a8b887 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -18,3 +18,4 @@ EXTRA_DIST += example.org-multiple-nsec3param.zone
EXTRA_DIST += example.org-nsec3-signed.zone
EXTRA_DIST += example.org-nsec3-signed-no-param.zone
EXTRA_DIST += example.org-out-of-zone.zone
+EXTRA_DIST += example.org-wildcard-ns.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone
new file mode 100644
index 0000000000..2933515ee9
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard NS names
+
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+*.example.org. 3600 IN NS ns1.example.org.
From 15bdb89898addbb7149479a083af674c545755d7 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 07:02:58 +0530
Subject: [PATCH 120/199] [2108] Check that loading a zone with wildcard DNAME
names throws an exception
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 9 +++++++++
src/lib/datasrc/memory/tests/testdata/Makefile.am | 1 +
.../tests/testdata/example.org-wildcard-dname.zone | 4 ++++
3 files changed, 14 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 69bf5baf48..64214d978d 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -299,6 +299,15 @@ TEST_F(MemoryClientTest, loadWildcardNSThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
+ // Wildcard NS names should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-wildcard-dname.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index a674a8b887..ad810b0e05 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -19,3 +19,4 @@ EXTRA_DIST += example.org-nsec3-signed.zone
EXTRA_DIST += example.org-nsec3-signed-no-param.zone
EXTRA_DIST += example.org-out-of-zone.zone
EXTRA_DIST += example.org-wildcard-ns.zone
+EXTRA_DIST += example.org-wildcard-dname.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone
new file mode 100644
index 0000000000..0d03b0d5ae
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard DNAME names
+
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
+*.example.org. 3600 IN DNAME dname.example.com.
From 46286a6732d6adf6f1640ad4ad6b7360a279fea4 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 07:14:04 +0530
Subject: [PATCH 121/199] [2108] Fix RRType in last commit comment
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 64214d978d..ff4a0a7bc4 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -300,7 +300,7 @@ TEST_F(MemoryClientTest, loadWildcardNSThrows) {
}
TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
- // Wildcard NS names should throw
+ // Wildcard DNAME names should throw
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-dname.zone"),
From 2d47ae95847e1088b1458f7d099093d2f5c8d9ef Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 07:17:22 +0530
Subject: [PATCH 122/199] [2108] Check that loading a zone with wildcard NSEC3
names throws an exception
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 9 +++++++++
src/lib/datasrc/memory/tests/testdata/Makefile.am | 1 +
.../tests/testdata/example.org-wildcard-nsec3.zone | 4 ++++
3 files changed, 14 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index ff4a0a7bc4..2bcb3f7706 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -308,6 +308,15 @@ TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
+ // Wildcard NSEC3 names should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-wildcard-nsec3.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index ad810b0e05..02a23e1eb7 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -20,3 +20,4 @@ EXTRA_DIST += example.org-nsec3-signed-no-param.zone
EXTRA_DIST += example.org-out-of-zone.zone
EXTRA_DIST += example.org-wildcard-ns.zone
EXTRA_DIST += example.org-wildcard-dname.zone
+EXTRA_DIST += example.org-wildcard-nsec3.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone
new file mode 100644
index 0000000000..feee116036
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard NS names
+
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
+*.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
From 41eff487aee5315bdb63b805d1e3e9efe13118f4 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 07:28:37 +0530
Subject: [PATCH 123/199] [2108] Check that loading a zone containing NSEC3
names with invalid number of labels throws
---
.../memory/tests/memory_client_unittest.cc | 18 ++++++++++++++++++
.../datasrc/memory/tests/testdata/Makefile.am | 2 ++
.../example.org-nsec3-fewer-labels.zone | 3 +++
.../example.org-nsec3-more-labels.zone | 3 +++
4 files changed, 26 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 2bcb3f7706..032b9654a4 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -317,6 +317,24 @@ TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
+ // NSEC3 names with labels != (origin_labels + 1) should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-nsec3-fewer-labels.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
+ // NSEC3 names with labels != (origin_labels + 1) should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-nsec3-more-labels.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 02a23e1eb7..721448a416 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -21,3 +21,5 @@ EXTRA_DIST += example.org-out-of-zone.zone
EXTRA_DIST += example.org-wildcard-ns.zone
EXTRA_DIST += example.org-wildcard-dname.zone
EXTRA_DIST += example.org-wildcard-nsec3.zone
+EXTRA_DIST += example.org-nsec3-fewer-labels.zone
+EXTRA_DIST += example.org-nsec3-more-labels.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone
new file mode 100644
index 0000000000..0221269a9b
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone
@@ -0,0 +1,3 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091001 7200 3600 2592000 1200
+example.org. 1200 IN NSEC3 1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone
new file mode 100644
index 0000000000..efebcfbf6d
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone
@@ -0,0 +1,3 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091002 7200 3600 2592000 1200
+a.b.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
From 3f0eb8fec78587398baa9964c344330b77a37f9e Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 09:36:53 +0530
Subject: [PATCH 124/199] [2108] If there's an exception, clear last_rrset_
---
src/lib/datasrc/memory/memory_client.cc | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index fb2a8e2e30..57138eedd3 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -548,11 +548,16 @@ InMemoryClient::InMemoryClientImpl::load(
assert(!last_rrset_);
- rrset_installer(boost::bind(&InMemoryClientImpl::addFromLoad, this,
- _1, zone_name, holder.get()));
-
- // Add any last RRset that was left
- addRdataSet(zone_name, *holder.get(), ConstRRsetPtr(), ConstRRsetPtr());
+ try {
+ rrset_installer(boost::bind(&InMemoryClientImpl::addFromLoad, this,
+ _1, zone_name, holder.get()));
+ // Add any last RRset that was left
+ addRdataSet(zone_name, *holder.get(),
+ ConstRRsetPtr(), ConstRRsetPtr());
+ } catch (...) {
+ last_rrset_ = ConstRRsetPtr();
+ throw;
+ }
assert(!last_rrset_);
From 083e6836264daff5da8aa95dff7927d0f37f0e43 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 09:37:26 +0530
Subject: [PATCH 125/199] [2108] Fix context check when adding a CNAME record
---
src/lib/datasrc/memory/memory_client.cc | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 57138eedd3..e21fd48418 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -178,11 +178,14 @@ public:
// owner name except with NSEC, which is the only RR that can coexist
// with CNAME (and also RRSIG, which is handled separately)
if (rrset.getType() == RRType::CNAME()) {
- if (RdataSet::find(set, RRType::NSEC()) != NULL) {
- LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
- arg(rrset.getName());
- isc_throw(AddError, "CNAME can't be added with other data for "
- << rrset.getName());
+ for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
+ if (sp->type != RRType::NSEC()) {
+ LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
+ arg(rrset.getName());
+ isc_throw(AddError, "CNAME can't be added with "
+ << sp->type << " RRType for "
+ << rrset.getName());
+ }
}
} else if ((rrset.getType() != RRType::NSEC()) &&
(RdataSet::find(set, RRType::CNAME()) != NULL)) {
From e898d07a4540cc9783779f0f39ddcf8264419068 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 09:37:55 +0530
Subject: [PATCH 126/199] [2108] Add CNAME+other tests (which should throw)
---
.../memory/tests/memory_client_unittest.cc | 15 +++++++++++++++
src/lib/datasrc/memory/tests/testdata/Makefile.am | 5 +++--
.../example.org-cname-and-not-nsec-1.zone | 4 ++++
.../example.org-cname-and-not-nsec-2.zone | 4 ++++
4 files changed, 26 insertions(+), 2 deletions(-)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 032b9654a4..e16431bd1e 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -335,6 +335,21 @@ TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
+ // CNAME and not NSEC should throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-cname-and-not-nsec-1.zone"),
+ InMemoryClient::AddError);
+
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-cname-and-not-nsec-2.zone"),
+ InMemoryClient::AddError);
+
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 721448a416..23429a4e3b 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -21,5 +21,6 @@ EXTRA_DIST += example.org-out-of-zone.zone
EXTRA_DIST += example.org-wildcard-ns.zone
EXTRA_DIST += example.org-wildcard-dname.zone
EXTRA_DIST += example.org-wildcard-nsec3.zone
-EXTRA_DIST += example.org-nsec3-fewer-labels.zone
-EXTRA_DIST += example.org-nsec3-more-labels.zone
+EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
new file mode 100644
index 0000000000..d44762d785
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
@@ -0,0 +1,4 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091009 7200 3600 2592000 1200
+a.example.org. 7200 IN A 192.168.0.1
+a.example.org. 3600 IN CNAME foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
new file mode 100644
index 0000000000..bca72cb499
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
@@ -0,0 +1,4 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091007 7200 3600 2592000 1200
+a.example.org. 3600 IN CNAME foo.example.com.
+a.example.org. 7200 IN A 192.168.0.1
From f4ceb192ddc140409230eef5ecc55a13f04059f5 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 09:41:50 +0530
Subject: [PATCH 127/199] [2108] Fix zone file comments
---
.../memory/tests/testdata/example.org-cname-and-not-nsec-1.zone | 2 +-
.../memory/tests/testdata/example.org-cname-and-not-nsec-2.zone | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
index d44762d785..5533663f69 100644
--- a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
@@ -1,4 +1,4 @@
-;; NSEC3 names with labels != (origin_labels + 1)
+;; CNAME + other is an error
example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091009 7200 3600 2592000 1200
a.example.org. 7200 IN A 192.168.0.1
a.example.org. 3600 IN CNAME foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
index bca72cb499..966aeeb9a5 100644
--- a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
@@ -1,4 +1,4 @@
-;; NSEC3 names with labels != (origin_labels + 1)
+;; CNAME + other is an error
example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091007 7200 3600 2592000 1200
a.example.org. 3600 IN CNAME foo.example.com.
a.example.org. 7200 IN A 192.168.0.1
From a376d4a632d9510ba8f4175b4221b245b812d65b Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 09:55:26 +0530
Subject: [PATCH 128/199] [2108] Add DNAME+NS tests
---
.../memory/tests/memory_client_unittest.cc | 34 +++++++++++++++++++
.../datasrc/memory/tests/testdata/Makefile.am | 4 +++
.../testdata/example.org-dname-ns-apex-1.zone | 4 +++
.../testdata/example.org-dname-ns-apex-2.zone | 4 +++
.../example.org-dname-ns-nonapex-1.zone | 4 +++
.../example.org-dname-ns-nonapex-2.zone | 4 +++
6 files changed, 54 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index e16431bd1e..771f036d07 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -350,6 +350,40 @@ TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
// Teardown checks for memory segment leaks
}
+TEST_F(MemoryClientTest, loadDNAMEAndNSApex1) {
+ // DNAME + NS (apex) is OK
+ client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-dname-ns-apex-1.zone");
+ // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSApex2) {
+ // DNAME + NS (apex) is OK (reverse order)
+ client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-dname-ns-apex-2.zone");
+ // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
+ // DNAME + NS (non-apex) must throw
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-dname-ns-nonapex-1.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
+ // DNAME + NS (non-apex) must throw (reverse order)
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR
+ "/example.org-dname-ns-nonapex-2.zone"),
+ InMemoryClient::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 23429a4e3b..8e0c2c8583 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -24,3 +24,7 @@ EXTRA_DIST += example.org-wildcard-nsec3.zone
EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-1.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-2.zone
+EXTRA_DIST += example.org-dname-ns-apex-1.zone
+EXTRA_DIST += example.org-dname-ns-apex-2.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone
new file mode 100644
index 0000000000..f57c25d3f2
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (apex)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
+example.org. 3600 IN DNAME foo.example.com.
+example.org. 3600 IN NS bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone
new file mode 100644
index 0000000000..bb3f1918d7
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (apex)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091016 7200 3600 2592000 1200
+example.org. 3600 IN NS bar.example.com.
+example.org. 3600 IN DNAME foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone
new file mode 100644
index 0000000000..68a980553d
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (non-apex)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091014 7200 3600 2592000 1200
+ns1.example.org. 3600 IN DNAME foo.example.com.
+ns1.example.org. 3600 IN NS bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone
new file mode 100644
index 0000000000..1b671dd1d9
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (non-apex)
+example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
+ns1.example.org. 3600 IN NS bar.example.com.
+ns1.example.org. 3600 IN DNAME foo.example.com.
From 72f8b8a0db78bab56f8efb0f344fc8961f9adadc Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 10:47:54 +0530
Subject: [PATCH 129/199] [2108] getTTL() is unimplemented in TreeNodeRRset
For now, let's use RRTTL(0) and revisit it.
---
src/lib/datasrc/memory/memory_client.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index e21fd48418..12e68df463 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -839,7 +839,7 @@ public:
RRsetPtr result(new RRset(rrset_->getName(),
rrset_->getClass(),
rrset_->getType(),
- rrset_->getTTL()));
+ RRTTL(0)));
result->addRdata(rdata_iterator_->getCurrent());
rdata_iterator_->next();
if (rdata_iterator_->isLast()) {
From c531154142d7466163731429af8050ede78bc423 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 10:48:04 +0530
Subject: [PATCH 130/199] [2108] Fix comment
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 771f036d07..18774be651 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -468,7 +468,7 @@ TEST_F(MemoryClientTest, getIterator) {
EXPECT_TRUE(rrset_soa);
EXPECT_EQ(RRType::SOA(), rrset_soa->getType());
- // There's nothing else in this zone
+ // There's nothing else in this iterator
EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
// Iterating past the end should result in an exception
From f60ea8d945a1c503670418c7e3f6cc57e5b82ee1 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 10:48:20 +0530
Subject: [PATCH 131/199] [2108] Test iterator with separate_rrs=true
---
.../memory/tests/memory_client_unittest.cc | 43 +++++++++++++++++++
.../datasrc/memory/tests/testdata/Makefile.am | 1 +
.../tests/testdata/example.org-multiple.zone | 4 ++
3 files changed, 48 insertions(+)
create mode 100644 src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 18774be651..ee747a31cc 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -475,6 +475,49 @@ TEST_F(MemoryClientTest, getIterator) {
EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
}
+TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
+ client_->load(Name("example.org"),
+ TEST_DATA_DIR "/example.org-multiple.zone");
+
+ // separate_rrs = false
+ ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+ // First we have the SOA
+ ConstRRsetPtr rrset(iterator->getNextRRset());
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+ // Only one RRType::A() RRset
+ rrset = iterator->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::A(), rrset->getType());
+
+ // There's nothing else in this zone
+ EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+
+
+ // separate_rrs = true
+ ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
+
+ // First we have the SOA
+ rrset = iterator2->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+ // First RRType::A() RRset
+ rrset = iterator2->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::A(), rrset->getType());
+
+ // Second RRType::A() RRset
+ rrset = iterator2->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::A(), rrset->getType());
+
+ // There's nothing else in this iterator
+ EXPECT_EQ(ConstRRsetPtr(), iterator2->getNextRRset());
+}
+
TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 8e0c2c8583..17fb97a964 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -3,6 +3,7 @@ CLEANFILES = *.copied
EXTRA_DIST = empty.zone
EXTRA_DIST += example.org.zone
EXTRA_DIST += example.org-empty.zone
+EXTRA_DIST += example.org-multiple.zone
EXTRA_DIST += example.org-broken1.zone
EXTRA_DIST += example.org-broken2.zone
EXTRA_DIST += example.org-rrsig-follows-nothing.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone
new file mode 100644
index 0000000000..f473ae6e0c
--- /dev/null
+++ b/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone
@@ -0,0 +1,4 @@
+;; Multiple RDATA for testing separate RRs iterator
+example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+a.example.org. 3600 IN A 192.168.0.1
+a.example.org. 3600 IN A 192.168.0.2
From a727e666876aa6ec02cc9d736b2735c4d021fca4 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 11:06:29 +0530
Subject: [PATCH 132/199] [2108] Implement TreeNodeRRset::getTTL()
This is used in the iterator when separating RRs.
---
.../memory/tests/treenode_rrset_unittest.cc | 16 +++++++++-------
src/lib/datasrc/memory/treenode_rrset.cc | 10 ++++++++--
src/lib/datasrc/memory/treenode_rrset.h | 4 +++-
3 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
index cf486bf9da..c83c034366 100644
--- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
+++ b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
@@ -138,11 +138,13 @@ protected:
void
checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
const RRClass& expected_class, const RRType& expected_type,
+ const uint32_t expected_ttl,
size_t expected_rdatacount, size_t expected_sigcount)
{
EXPECT_EQ(expected_name, actual_rrset.getName());
EXPECT_EQ(expected_class, actual_rrset.getClass());
EXPECT_EQ(expected_type, actual_rrset.getType());
+ EXPECT_EQ(RRTTL(expected_ttl), actual_rrset.getTTL());
EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
}
@@ -150,31 +152,31 @@ checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
TEST_F(TreeNodeRRsetTest, create) {
// Constructed with RRSIG, and it should be visible.
checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true),
- www_name_, rrclass_, RRType::A(), 2, 1);
+ www_name_, rrclass_, RRType::A(), 3600, 2, 1);
// Constructed with RRSIG, and it should be invisible.
checkBasicFields(TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false),
- www_name_, rrclass_, RRType::A(), 2, 0);
+ www_name_, rrclass_, RRType::A(), 3600, 2, 0);
// Constructed without RRSIG, and it would be visible (but of course won't)
checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_, true),
- origin_name_, rrclass_, RRType::NS(), 1, 0);
+ origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
// Constructed without RRSIG, and it should be visible
checkBasicFields(TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
false),
- origin_name_, rrclass_, RRType::NS(), 1, 0);
+ origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
// RRSIG-only case (note the RRset's type is covered type)
checkBasicFields(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_,
true),
- www_name_, rrclass_, RRType::TXT(), 0, 1);
+ www_name_, rrclass_, RRType::TXT(), 3600, 0, 1);
// RRSIG-only case (note the RRset's type is covered type), but it's
// invisible
checkBasicFields(TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_,
false),
- www_name_, rrclass_, RRType::TXT(), 0, 0);
+ www_name_, rrclass_, RRType::TXT(), 3600, 0, 0);
// Wildcard substitution
checkBasicFields(TreeNodeRRset(match_name_, rrclass_,
wildcard_node_, wildcard_rdataset_,
true),
- match_name_, rrclass_, RRType::A(), 2, 1);
+ match_name_, rrclass_, RRType::A(), 3600, 2, 1);
}
// Templated if and when we support OutputBuffer version of toWire().
diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc
index 6fc6b66682..1f4bc1d02e 100644
--- a/src/lib/datasrc/memory/treenode_rrset.cc
+++ b/src/lib/datasrc/memory/treenode_rrset.cc
@@ -46,7 +46,7 @@ TreeNodeRRset::TreeNodeRRset(const dns::Name& realname,
bool dnssec_ok) :
node_(node), rdataset_(rdataset),
rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
- dnssec_ok_(dnssec_ok), name_(NULL)
+ dnssec_ok_(dnssec_ok), name_(NULL), ttl_(NULL)
{
const LabelSequence labels(realname);
const size_t labels_storangelen = labels.getSerializedLength();
@@ -69,7 +69,13 @@ TreeNodeRRset::getName() const {
const RRTTL&
TreeNodeRRset::getTTL() const {
- isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+ if (ttl_ == NULL) {
+ util::InputBuffer ttl_buffer(rdataset_->getTTLData(),
+ sizeof(uint32_t));
+ ttl_ = new RRTTL(ttl_buffer);
+ }
+
+ return (*ttl_);
}
void
diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h
index 1f52124386..91f81e859b 100644
--- a/src/lib/datasrc/memory/treenode_rrset.h
+++ b/src/lib/datasrc/memory/treenode_rrset.h
@@ -105,7 +105,7 @@ public:
const RdataSet* rdataset, bool dnssec_ok) :
node_(node), rdataset_(rdataset),
rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
- dnssec_ok_(dnssec_ok), name_(NULL), realname_buf_(NULL)
+ dnssec_ok_(dnssec_ok), name_(NULL), realname_buf_(NULL), ttl_(NULL)
{}
/// \brief Constructor for wildcard-expanded owner name.
@@ -126,6 +126,7 @@ public:
virtual ~TreeNodeRRset() {
delete[] realname_buf_;
+ delete ttl_;
delete name_;
}
@@ -251,6 +252,7 @@ private:
const bool dnssec_ok_;
mutable dns::Name* name_;
uint8_t* realname_buf_;
+ mutable dns::RRTTL* ttl_;
};
} // namespace memory
From 5bd8df4b94383665c2c6de44436b3eeedae7f2d4 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 11:06:44 +0530
Subject: [PATCH 133/199] Revert "[2108] getTTL() is unimplemented in
TreeNodeRRset"
This reverts commit 72f8b8a0db78bab56f8efb0f344fc8961f9adadc.
---
src/lib/datasrc/memory/memory_client.cc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 12e68df463..e21fd48418 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -839,7 +839,7 @@ public:
RRsetPtr result(new RRset(rrset_->getName(),
rrset_->getClass(),
rrset_->getType(),
- RRTTL(0)));
+ rrset_->getTTL()));
result->addRdata(rdata_iterator_->getCurrent());
rdata_iterator_->next();
if (rdata_iterator_->isLast()) {
From eb66b3c19f083d918a536b422376217851896d0f Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 11:09:21 +0530
Subject: [PATCH 134/199] [2108] Sort zone files in Makefile.am
---
.../datasrc/memory/tests/testdata/Makefile.am | 37 ++++++++++---------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
index 17fb97a964..9fb99866a3 100644
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ b/src/lib/datasrc/memory/tests/testdata/Makefile.am
@@ -3,29 +3,30 @@ CLEANFILES = *.copied
EXTRA_DIST = empty.zone
EXTRA_DIST += example.org.zone
EXTRA_DIST += example.org-empty.zone
-EXTRA_DIST += example.org-multiple.zone
+
EXTRA_DIST += example.org-broken1.zone
EXTRA_DIST += example.org-broken2.zone
-EXTRA_DIST += example.org-rrsig-follows-nothing.zone
-EXTRA_DIST += example.org-rrsig-name-unmatched.zone
-EXTRA_DIST += example.org-rrsig-type-unmatched.zone
-EXTRA_DIST += example.org-rrsigs.zone
-EXTRA_DIST += example.org-duplicate-type.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
+EXTRA_DIST += example.org-dname-ns-apex-1.zone
+EXTRA_DIST += example.org-dname-ns-apex-2.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-1.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-2.zone
EXTRA_DIST += example.org-duplicate-type-bad.zone
+EXTRA_DIST += example.org-duplicate-type.zone
EXTRA_DIST += example.org-multiple-cname.zone
EXTRA_DIST += example.org-multiple-dname.zone
EXTRA_DIST += example.org-multiple-nsec3.zone
EXTRA_DIST += example.org-multiple-nsec3param.zone
-EXTRA_DIST += example.org-nsec3-signed.zone
-EXTRA_DIST += example.org-nsec3-signed-no-param.zone
-EXTRA_DIST += example.org-out-of-zone.zone
-EXTRA_DIST += example.org-wildcard-ns.zone
-EXTRA_DIST += example.org-wildcard-dname.zone
-EXTRA_DIST += example.org-wildcard-nsec3.zone
+EXTRA_DIST += example.org-multiple.zone
EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
-EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
-EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
-EXTRA_DIST += example.org-dname-ns-nonapex-1.zone
-EXTRA_DIST += example.org-dname-ns-nonapex-2.zone
-EXTRA_DIST += example.org-dname-ns-apex-1.zone
-EXTRA_DIST += example.org-dname-ns-apex-2.zone
+EXTRA_DIST += example.org-nsec3-signed-no-param.zone
+EXTRA_DIST += example.org-nsec3-signed.zone
+EXTRA_DIST += example.org-out-of-zone.zone
+EXTRA_DIST += example.org-rrsig-follows-nothing.zone
+EXTRA_DIST += example.org-rrsig-name-unmatched.zone
+EXTRA_DIST += example.org-rrsig-type-unmatched.zone
+EXTRA_DIST += example.org-rrsigs.zone
+EXTRA_DIST += example.org-wildcard-dname.zone
+EXTRA_DIST += example.org-wildcard-ns.zone
+EXTRA_DIST += example.org-wildcard-nsec3.zone
From 8716a098a9205bf1aeae4dd61d7c2e4fb4956c47 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 12:08:06 +0530
Subject: [PATCH 135/199] [2108] Add unique prefix to datasrc::memory message
IDs
---
src/lib/datasrc/memory/memory_client.cc | 28 ++++++++++----------
src/lib/datasrc/memory/memory_messages.mes | 30 +++++++++++-----------
2 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index e21fd48418..32b9d2b128 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -147,7 +147,7 @@ public:
l > origin_labels;
--l, wname = wname.split(1)) {
if (wname.isWildcard()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_WILDCARD).
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_WILDCARD).
arg(name);
// Ensure a separate level exists for the "wildcarding" name,
@@ -180,7 +180,7 @@ public:
if (rrset.getType() == RRType::CNAME()) {
for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
if (sp->type != RRType::NSEC()) {
- LOG_ERROR(logger, DATASRC_MEM_CNAME_TO_NONEMPTY).
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
arg(rrset.getName());
isc_throw(AddError, "CNAME can't be added with "
<< sp->type << " RRType for "
@@ -189,7 +189,7 @@ public:
}
} else if ((rrset.getType() != RRType::NSEC()) &&
(RdataSet::find(set, RRType::CNAME()) != NULL)) {
- LOG_ERROR(logger, DATASRC_MEM_CNAME_COEXIST).arg(rrset.getName());
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
isc_throw(AddError, "CNAME and " << rrset.getType() <<
" can't coexist for " << rrset.getName());
}
@@ -207,7 +207,7 @@ public:
(rrset.getType() == RRType::NS() &&
RdataSet::find(set, RRType::DNAME()) != NULL)))
{
- LOG_ERROR(logger, DATASRC_MEM_DNAME_NS).arg(rrset.getName());
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
"domain " << rrset.getName());
}
@@ -233,7 +233,7 @@ public:
// XXX: this is not only for CNAME or DNAME. We should generalize
// this code for all other "singleton RR types" (such as SOA) in a
// separate task.
- LOG_ERROR(logger, DATASRC_MEM_SINGLETON).arg(rrset->getName()).
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
arg(rrset->getType());
isc_throw(AddError, "multiple RRs of singleton type for "
<< rrset->getName());
@@ -251,7 +251,7 @@ public:
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
compare.getRelation() != NameComparisonResult::EQUAL)
{
- LOG_ERROR(logger, DATASRC_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
arg(zone_name);
isc_throw(OutOfZone, "The name " << rrset->getName() <<
" is not contained in zone " << zone_name);
@@ -267,13 +267,13 @@ public:
// behavior.
if (rrset->getName().isWildcard()) {
if (rrset->getType() == RRType::NS()) {
- LOG_ERROR(logger, DATASRC_MEM_WILDCARD_NS).
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
arg(rrset->getName());
isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
rrset->getName());
}
if (rrset->getType() == RRType::DNAME()) {
- LOG_ERROR(logger, DATASRC_MEM_WILDCARD_DNAME).
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
arg(rrset->getName());
isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
rrset->getName());
@@ -289,7 +289,7 @@ public:
(rrset->getName().isWildcard() ||
rrset->getName().getLabelCount() !=
zone_name.getLabelCount() + 1)) {
- LOG_ERROR(logger, DATASRC_BAD_NSEC3_NAME).
+ LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
arg(rrset->getName());
isc_throw(AddError, "Invalid NSEC3 owner name: " <<
rrset->getName());
@@ -498,7 +498,7 @@ public:
addValidation(zone_name, rrset);
// OK, can add the RRset.
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
if (rrset->getType() == RRType::NSEC3()) {
@@ -572,7 +572,7 @@ InMemoryClient::InMemoryClientImpl::load(
// process only adds new nodes (and their data), so this assertion
// should hold.
if (RdataSet::find(set, RRType::NSEC3PARAM()) == NULL) {
- LOG_WARN(logger, DATASRC_MEM_NO_NSEC3PARAM).
+ LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
arg(zone_name).arg(rrclass_);
}
}
@@ -585,7 +585,7 @@ InMemoryClient::InMemoryClientImpl::load(
"Won't create an empty zone for: " << zone_name);
}
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
arg(zone_name).arg(rrclass_.toText());
// Set the filename in file_name_tree_ now, so that getFileName()
@@ -688,7 +688,7 @@ InMemoryClient::getZoneCount() const {
isc::datasrc::memory::ZoneTable::FindResult
InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(zone_name);
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
return (result);
}
@@ -705,7 +705,7 @@ InMemoryClient::findZone(const isc::dns::Name&) const {
result::Result
InMemoryClient::load(const isc::dns::Name& zone_name,
const std::string& filename) {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(zone_name).
+ LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
arg(filename);
return (impl_->load(zone_name, filename,
diff --git a/src/lib/datasrc/memory/memory_messages.mes b/src/lib/datasrc/memory/memory_messages.mes
index 6fe63c79c3..a66297c334 100644
--- a/src/lib/datasrc/memory/memory_messages.mes
+++ b/src/lib/datasrc/memory/memory_messages.mes
@@ -16,62 +16,62 @@ $NAMESPACE isc::datasrc::memory
# \brief Messages for the data source memory library
-% DATASRC_MEM_ADD_WILDCARD adding wildcards for '%1'
+% DATASRC_MEMORY_MEM_ADD_WILDCARD adding wildcards for '%1'
This is a debug message issued during the processing of a wildcard
name. The internal domain name tree is scanned and some nodes are
specially marked to allow the wildcard lookup to succeed.
-% DATASRC_MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'
+% DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY can't add CNAME to domain with other data in '%1'
Someone or something tried to add a CNAME into a domain that already contains
some other data. But the protocol forbids coexistence of CNAME with anything
(RFC 1034, section 3.6.2). This indicates a problem with provided data.
-% DATASRC_MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'
+% DATASRC_MEMORY_MEM_CNAME_COEXIST can't add data to CNAME in domain '%1'
This is the same problem as in MEM_CNAME_TO_NONEMPTY, but it happened the
other way around -- adding some other data to CNAME.
-% DATASRC_MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%1'
+% DATASRC_MEMORY_MEM_DNAME_NS DNAME and NS can't coexist in non-apex domain '%1'
A request was made for DNAME and NS records to be put into the same
domain which is not the apex (the top of the zone). This is forbidden
by RFC 2672 (section 3) and indicates a problem with provided data.
-% DATASRC_MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'
+% DATASRC_MEMORY_MEM_SINGLETON trying to add multiple RRs for domain '%1' and type '%2'
Some resource types are singletons -- only one is allowed in a domain
(for example CNAME or SOA). This indicates a problem with provided data.
-% DATASRC_MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'
+% DATASRC_MEMORY_MEM_OUT_OF_ZONE domain '%1' doesn't belong to zone '%2'
It was attempted to add the domain into a zone that shouldn't have it
(eg. the domain is not subdomain of the zone origin). This indicates a
problem with provided data.
-% DATASRC_MEM_WILDCARD_NS NS record in wildcard domain '%1'
+% DATASRC_MEMORY_MEM_WILDCARD_NS NS record in wildcard domain '%1'
The software refuses to load NS records into a wildcard domain. It isn't
explicitly forbidden, but the protocol is ambiguous about how this should
behave and BIND 9 refuses that as well. Please describe your intention using
different tools.
-% DATASRC_MEM_WILDCARD_DNAME DNAME record in wildcard domain '%1'
+% DATASRC_MEMORY_MEM_WILDCARD_DNAME DNAME record in wildcard domain '%1'
The software refuses to load DNAME records into a wildcard domain. It isn't
explicitly forbidden, but the protocol is ambiguous about how this should
behave and BIND 9 refuses that as well. Please describe your intention using
different tools.
-% DATASRC_BAD_NSEC3_NAME NSEC3 record has a bad owner name '%1'
+% DATASRC_MEMORY_BAD_NSEC3_NAME NSEC3 record has a bad owner name '%1'
The software refuses to load NSEC3 records into a wildcard domain or
the owner name has two or more labels below the zone origin.
It isn't explicitly forbidden, but no sane zone wouldn have such names
for NSEC3. BIND 9 also refuses NSEC3 at wildcard, so this behavior is
compatible with BIND 9.
-% DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
+% DATASRC_MEMORY_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
Debug information. An RRset is being added to the in-memory data source.
-% DATASRC_MEM_DUP_RRSET duplicate RRset '%1/%2'
+% DATASRC_MEMORY_MEM_DUP_RRSET duplicate RRset '%1/%2'
An RRset is being inserted into in-memory data source for a second time. The
original version must be removed first. Note that loading master files where an
RRset is split into multiple locations is not supported yet.
-% DATASRC_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2
+% DATASRC_MEMORY_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2
The in-memory data source has loaded a zone signed with NSEC3 RRs,
but it doesn't have a NSEC3PARAM RR at the zone origin. It's likely that
the zone is somehow broken, but this RR is not necessarily needed for
@@ -79,12 +79,12 @@ handling lookups with NSEC3 in this data source, so it accepts the given
content of the zone. Nevertheless the administrator should look into
the integrity of the zone data.
-% DATASRC_MEM_ADD_ZONE adding zone '%1/%2'
+% DATASRC_MEMORY_MEM_ADD_ZONE adding zone '%1/%2'
Debug information. A zone is being added into the in-memory data source.
-% DATASRC_MEM_FIND_ZONE looking for zone '%1'
+% DATASRC_MEMORY_MEM_FIND_ZONE looking for zone '%1'
Debug information. A zone object for this zone is being searched for in the
in-memory data source.
-% DATASRC_MEM_LOAD loading zone '%1' from file '%2'
+% DATASRC_MEMORY_MEM_LOAD loading zone '%1' from file '%2'
Debug information. The content of master file is being loaded into the memory.
From 4171ba94fead572dbc4de66f9a35380680d55fa7 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 12:43:10 +0530
Subject: [PATCH 136/199] [2108] Wrap lines
---
src/lib/datasrc/memory/memory_client.cc | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 32b9d2b128..7758e3cae9 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -147,8 +147,8 @@ public:
l > origin_labels;
--l, wname = wname.split(1)) {
if (wname.isWildcard()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_WILDCARD).
- arg(name);
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
// Ensure a separate level exists for the "wildcarding" name,
// and mark the node as "wild".
@@ -189,7 +189,8 @@ public:
}
} else if ((rrset.getType() != RRType::NSEC()) &&
(RdataSet::find(set, RRType::CNAME()) != NULL)) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
isc_throw(AddError, "CNAME and " << rrset.getType() <<
" can't coexist for " << rrset.getName());
}
@@ -233,7 +234,8 @@ public:
// XXX: this is not only for CNAME or DNAME. We should generalize
// this code for all other "singleton RR types" (such as SOA) in a
// separate task.
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
arg(rrset->getType());
isc_throw(AddError, "multiple RRs of singleton type for "
<< rrset->getName());
@@ -251,7 +253,8 @@ public:
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
compare.getRelation() != NameComparisonResult::EQUAL)
{
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
arg(zone_name);
isc_throw(OutOfZone, "The name " << rrset->getName() <<
" is not contained in zone " << zone_name);
@@ -688,7 +691,8 @@ InMemoryClient::getZoneCount() const {
isc::datasrc::memory::ZoneTable::FindResult
InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
return (result);
}
From dd5485e6973a8ebc6fc99727ac3bc8903c8fce3b Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 12:53:39 +0530
Subject: [PATCH 137/199] [2108] Add unittest for load() which accepts an
iterator
---
.../memory/tests/memory_client_unittest.cc | 69 +++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index ee747a31cc..b86a3bd05d 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -32,6 +32,8 @@
#include
#include
+#include
+
#include
#include // for bad_alloc
@@ -40,6 +42,7 @@ using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc;
using namespace isc::datasrc::memory;
+using namespace isc::testutils;
namespace {
// Memory segment specified for tests. It normally behaves like a "local"
@@ -63,6 +66,44 @@ private:
size_t throw_count_;
};
+static const char* rrset_data[] = {
+ "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600",
+ "a.example.org. 3600 IN A 192.168.0.1",
+ "a.example.org. 3600 IN MX 10 mail.example.org.",
+ NULL
+};
+
+class MockIterator : public ZoneIterator {
+private:
+ MockIterator() :
+ rrset_data_ptr_(rrset_data)
+ {
+ }
+
+ const char** rrset_data_ptr_;
+
+public:
+ virtual ConstRRsetPtr getNextRRset() {
+ if (*rrset_data_ptr_ == NULL) {
+ return (ConstRRsetPtr());
+ }
+
+ RRsetPtr result(textToRRset(*rrset_data_ptr_,
+ RRClass::IN(), Name("example.org")));
+ rrset_data_ptr_++;
+
+ return (result);
+ }
+
+ virtual ConstRRsetPtr getSOA() const {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+
+ static ZoneIteratorPtr makeIterator(void) {
+ return (ZoneIteratorPtr(new MockIterator()));
+ }
+};
+
class MemoryClientTest : public ::testing::Test {
protected:
MemoryClientTest() : zclass_(RRClass::IN()),
@@ -142,6 +183,34 @@ TEST_F(MemoryClientTest, load) {
TEST_DATA_DIR "/example.org.zone");
}
+TEST_F(MemoryClientTest, loadFromIterator) {
+ client_->load(Name("example.org"),
+ *MockIterator::makeIterator());
+
+ ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+ // First we have the SOA
+ ConstRRsetPtr rrset(iterator->getNextRRset());
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+ // RRType::MX() RRset
+ rrset = iterator->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::MX(), rrset->getType());
+
+ // RRType::A() RRset
+ rrset = iterator->getNextRRset();
+ EXPECT_TRUE(rrset);
+ EXPECT_EQ(RRType::A(), rrset->getType());
+
+ // There's nothing else in this iterator
+ EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+
+ // Iterating past the end should result in an exception
+ EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
+}
+
TEST_F(MemoryClientTest, loadNSEC3Signed) {
client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-nsec3-signed.zone");
From f1f2184dc4023a2cdd4157aefd3bdafdb164d586 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 13:11:13 +0530
Subject: [PATCH 138/199] [2108] Pass memory segment to InMemoryClient
constructor
---
src/lib/datasrc/memory/memory_client.cc | 11 +++++++----
src/lib/datasrc/memory/memory_client.h | 5 ++++-
.../datasrc/memory/tests/memory_client_unittest.cc | 2 +-
3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 7758e3cae9..5617690d29 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -87,7 +87,9 @@ private:
};
public:
- InMemoryClientImpl(RRClass rrclass) :
+ InMemoryClientImpl(util::MemorySegment& mem_sgmt,
+ RRClass rrclass) :
+ local_mem_sgmt_(mem_sgmt),
rrclass_(rrclass),
zone_count_(0),
zone_table_(ZoneTable::create(local_mem_sgmt_, rrclass)),
@@ -106,7 +108,7 @@ public:
// Memory segment to allocate/deallocate memory for the zone table.
// (This will eventually have to be abstract; for now we hardcode the
// specific derived segment class).
- util::MemorySegmentLocal local_mem_sgmt_;
+ util::MemorySegment& local_mem_sgmt_;
const RRClass rrclass_;
unsigned int zone_count_;
ZoneTable* zone_table_;
@@ -671,8 +673,9 @@ generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
}
}
-InMemoryClient::InMemoryClient(RRClass rrclass) :
- impl_(new InMemoryClientImpl(rrclass))
+InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
+ RRClass rrclass) :
+ impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
{}
InMemoryClient::~InMemoryClient() {
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 0c211c1dd4..a28125950f 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -15,6 +15,8 @@
#ifndef DATASRC_MEMORY_CLIENT_H
#define DATASRC_MEMORY_CLIENT_H 1
+#include
+
#include
#include
#include
@@ -62,7 +64,8 @@ public:
/// This constructor internally involves resource allocation, and if
/// it fails, a corresponding standard exception will be thrown.
/// It never throws an exception otherwise.
- InMemoryClient(isc::dns::RRClass rrclass);
+ InMemoryClient(util::MemorySegment& mem_sgmt,
+ isc::dns::RRClass rrclass);
/// The destructor.
~InMemoryClient();
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index b86a3bd05d..0290a28cb4 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -107,7 +107,7 @@ public:
class MemoryClientTest : public ::testing::Test {
protected:
MemoryClientTest() : zclass_(RRClass::IN()),
- client_(new InMemoryClient(zclass_))
+ client_(new InMemoryClient(mem_sgmt_, zclass_))
{}
~MemoryClientTest() {
if (client_ != NULL) {
From d976012056c29d07ad3ca563b7870a0ea07ca531 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 13:15:30 +0530
Subject: [PATCH 139/199] [2108] Test for segment leaks due to allocation
failures
---
.../datasrc/memory/tests/memory_client_unittest.cc | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 0290a28cb4..8a7f19ebfa 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -211,6 +211,18 @@ TEST_F(MemoryClientTest, loadFromIterator) {
EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
}
+TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
+ // Just to check that things get cleaned up
+
+ for (int i = 1; i < 16; i++) {
+ mem_sgmt_.setThrowCount(i);
+ EXPECT_THROW(client_->load(Name("example.org"),
+ TEST_DATA_DIR "/example.org.zone"),
+ std::bad_alloc);
+ }
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, loadNSEC3Signed) {
client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-nsec3-signed.zone");
From e3f72ac2caea7a75deb1b772d9681d6be3aad203 Mon Sep 17 00:00:00 2001
From: Mukund Sivaraman
Date: Mon, 10 Sep 2012 13:16:35 +0530
Subject: [PATCH 140/199] [2108] Remove TODO list
---
src/lib/datasrc/memory/tests/memory_client_unittest.cc | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
index 8a7f19ebfa..86dd674a5a 100644
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
@@ -738,10 +738,4 @@ TEST_F(MemoryClientTest, getJournalReaderNotImplemented) {
EXPECT_THROW(client_->getJournalReader(Name("."), 0, 0),
isc::NotImplemented);
}
-
-// TODO:
-// Add test for add() with separate_rrs=true
-// Add test for ZoneIterator variant of load()
-// Add test for leaks during allocation failures using TestMemorySegment
-// Iterate through an entire zone
}
From 0ebd6dbbd9af7ea20543a9813a9d38cc7a227935 Mon Sep 17 00:00:00 2001
From: Marcin Siodelski
Date: Mon, 10 Sep 2012 12:14:19 +0200
Subject: [PATCH 141/199] [2230] Added perfdhcp command line examples.
---
tests/tools/dhcp-ubench/dhcp-perf-guide.html | 234 ++++++++++++++--
tests/tools/dhcp-ubench/dhcp-perf-guide.xml | 265 +++++++++++++++++--
2 files changed, 460 insertions(+), 39 deletions(-)
diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.html b/tests/tools/dhcp-ubench/dhcp-perf-guide.html
index 60de83809b..27da0b1c0d 100644
--- a/tests/tools/dhcp-ubench/dhcp-perf-guide.html
+++ b/tests/tools/dhcp-ubench/dhcp-perf-guide.html
@@ -7,7 +7,7 @@
This document describes various aspects of DHCP performance,
measurements and tuning. It covers BIND 10 DHCP (codename Kea),
existing ISC DHCP4 software, perfdhcp (a DHCP performance
- measurement tool) and other related topics.
ISC would like to acknowledge generous support for
+ measurement tool) and other related topics.
ISC would like to acknowledge generous support for
BIND 10 development of DHCPv4 and DHCPv6 components provided
by Comcast.
This document is in its early stages of development. It is
@@ -196,7 +196,7 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
Multi-threaded or multi-process benchmark may be considered in
the future. It may be somewhat difficult as only some backends
support concurrent access.
-
There is a growing need to evaluate performance of DHCP servers in
different traffic conditions to understand their bottle necks.
This helps to elimante bugs in existing DHCP software as well
@@ -206,15 +206,15 @@ SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe7
mostly. However, the number of implemented features and parameters
exposed to the user make this tool useful for functional testing as
well.
-
The perfdhcp exposes the number of command line parameters to
control DHCP message exchanges. Currently they fall back to
the following categories:
Rate control - control how many DHCP exchanges
are initiated within a period of time. Tool can also simulate
- best effort conditions where it attempts to start as many
- exchanges as possible.
+ best effort conditions attempting to initiate as many DHCP
+ packet exchanges within a unit of time as possible.
Test exit specifiers - control the conditions when test
completes including number of initiated exchanges, test period or
@@ -367,7 +367,7 @@ The exit status is:
exchanges are not successfully completed.
-
In order to run performance test at least two separate systems
have to be installed: client and server. The first one has to have
perfdhcp tool installed, the latter has to have DHCP server
@@ -377,28 +377,224 @@ The exit status is:
impacted by the performance of VMs.
The DHCP operates on low port numbers (67 for DHCPv4 relays and
- 547 for DHCPv6) running perfdhcp with non-root priviliges will
+ 547 for DHCPv6). Running perfdhcp with non-root priviliges will
usually result in the error message similar to this:
$./perfdhcp -4 -l eth3 -r 100 all
Error running perfdhcp: Failed to bind socket 3 to 172.16.1.2/port=67
- perfdhcp exposes '-L' command line option that
- imposes use of custom local port and the following command line will
- work:
+ perfdhcp has the '-L' command line option that
+ imposes use of custom local port. Thus the following command
+ line will work:
$./perfdhcp -4 -l eth3 -r 100 -L 10067 all
but in the standard configuration no responses will be received
from the ISC DHCP server because server responds to default relay
port 67.
+ Alternative way to overcome this issue is to run perfdhcp as root.
- Alternative way to overcome the issue with lack of privileges
- to use default DHCP port number is to run perfdhcp as root.
-
- In this section the perfdhcp command line options examples
+ Currently, perfdhcp is seen from the server perspective as relay agent.
+ This simplifies its implementation (specifically there is no need to
+ receive traffic sent to braodcast addresses). This imposes that IPv4
+ address has to be set manually on the interface that will be used to
+ communicate with the server. For example, if DHCPv4 server is listening
+ on the interface connected to 172.16.1.0 subnet, interface on client
+ machine has to have network address assigned from the same subnet
+ on one of its interfaces connected to this subnet:
+
#ifconfig eth3 172.16.1.2. netmask 255.255.255.0 up
+
perfdhcp command line examples
+ In this section the perfdhcp command line examples
are presented as a quick start guide for new users. For the
detailed list of command line options refer to
the section called “Command line options”.
-
-
-
-
-