Commit 9b6f5440 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac1288'

parents e4b99333 36a5cd75
......@@ -628,21 +628,10 @@ class BoB:
# ... and start
return self.start_process("b10-resolver", resargs, self.c_channel_env)
def start_cmdctl(self):
"""
Starts the command control process
"""
args = ["b10-cmdctl"]
if self.cmdctl_port is not None:
args.append("--port=" + str(self.cmdctl_port))
if self.verbose:
args.append("-v")
return self.start_process("b10-cmdctl", args, self.c_channel_env,
self.cmdctl_port)
def start_xfrin(self):
# XXX: a quick-hack workaround. xfrin will implicitly use dynamically
# loadable data source modules, which will be installed in $(libdir).
def __ld_path_hack(self):
# XXX: a quick-hack workaround. xfrin/out will implicitly use
# dynamically loadable data source modules, which will be installed in
# $(libdir).
# On some OSes (including MacOS X and *BSDs) the main process (python)
# cannot find the modules unless they are located in a common shared
# object path or a path in the (DY)LD_LIBRARY_PATH. We should seek
......@@ -655,21 +644,44 @@ class BoB:
# the same as for the libexec path addition
# TODO: Once #1292 is finished, remove this method and the special
# component, use it as normal component.
c_channel_env = dict(self.c_channel_env)
env = dict(self.c_channel_env)
if ADD_LIBEXEC_PATH:
cur_path = os.getenv('DYLD_LIBRARY_PATH')
cur_path = '' if cur_path is None else ':' + cur_path
c_channel_env['DYLD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
env['DYLD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
cur_path = os.getenv('LD_LIBRARY_PATH')
cur_path = '' if cur_path is None else ':' + cur_path
c_channel_env['LD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
env['LD_LIBRARY_PATH'] = "@@LIBDIR@@" + cur_path
return env
def start_cmdctl(self):
"""
Starts the command control process
"""
args = ["b10-cmdctl"]
if self.cmdctl_port is not None:
args.append("--port=" + str(self.cmdctl_port))
if self.verbose:
args.append("-v")
return self.start_process("b10-cmdctl", args, self.c_channel_env,
self.cmdctl_port)
def start_xfrin(self):
# Set up the command arguments.
args = ['b10-xfrin']
if self.verbose:
args += ['-v']
return self.start_process("b10-xfrin", args, c_channel_env)
return self.start_process("b10-xfrin", args, self.__ld_path_hack())
def start_xfrout(self):
# Set up the command arguments.
args = ['b10-xfrout']
if self.verbose:
args += ['-v']
return self.start_process("b10-xfrout", args, self.__ld_path_hack())
def start_all_components(self):
"""
......
......@@ -15,7 +15,7 @@
"kind": "dispensable"
},
"b10-xfrin": { "special": "xfrin", "kind": "dispensable" },
"b10-xfrout": { "address": "Xfrout", "kind": "dispensable" },
"b10-xfrout": { "special": "xfrout", "kind": "dispensable" },
"b10-zonemgr": { "address": "Zonemgr", "kind": "dispensable" },
"b10-stats": { "address": "Stats", "kind": "dispensable" },
"b10-stats-httpd": {
......
......@@ -274,8 +274,7 @@ class MockBob(BoB):
return procinfo
def start_simple(self, name):
procmap = { 'b10-xfrout': self.start_xfrout,
'b10-zonemgr': self.start_zonemgr,
procmap = { 'b10-zonemgr': self.start_zonemgr,
'b10-stats': self.start_stats,
'b10-stats-httpd': self.start_stats_httpd,
'b10-cmdctl': self.start_cmdctl,
......@@ -475,7 +474,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
if start_auth:
config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
config['b10-xfrout'] = { 'kind': 'dispensable',
'address': 'Xfrout' }
'special': 'xfrout' }
config['b10-xfrin'] = { 'kind': 'dispensable', 'special': 'xfrin' }
config['b10-zonemgr'] = { 'kind': 'dispensable',
'address': 'Zonemgr' }
......
......@@ -10,7 +10,7 @@ LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$$$(ENV_LIBRARY_PATH)
else
# sunstudio needs the ds path even if not all paths are necessary
# Some systems need the ds path even if not all paths are necessary
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/datasrc/.libs
endif
......
......@@ -2,11 +2,18 @@ PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
PYTESTS = xfrout_test.py
noinst_SCRIPTS = $(PYTESTS)
EXTRA_DIST = testdata/test.sqlite3
# This one is actually not necessary, but added for reference
EXTRA_DIST += testdata/example.com
# If necessary (rare cases), explicitly specify paths to dynamic libraries
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/util/io/.libs:$(abs_top_builddir)/src/lib/datasrc/.libs:$(abs_top_builddir)/src/lib/acl/.libs:$$$(ENV_LIBRARY_PATH)
else
# Some systems need the ds path even if not all paths are necessary
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/datasrc/.libs
endif
# test using command-line arguments, so use check-local target instead of TESTS
......@@ -24,5 +31,6 @@ endif
B10_FROM_BUILD=$(abs_top_builddir) \
$(LIBRARY_PATH_PLACEHOLDER) \
PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_builddir)/src/bin/xfrout:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/util/io/.libs \
TESTDATASRCDIR=$(abs_srcdir)/testdata/ \
$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
done
;; This is the source of a zone stored in test.sqlite3. It's provided
;; for reference purposes only.
example.com. 3600 IN SOA a.dns.example.com. mail.example.com. 1 1 1 1 1
example.com. 3600 IN NS a.dns.example.com.
a.dns.example.com. 3600 IN A 192.0.2.1
a.dns.example.com. 7200 IN A 192.0.2.2
This diff is collapsed.
......@@ -22,7 +22,7 @@ import isc.cc
import threading
import struct
import signal
from isc.datasrc import sqlite3_ds
from isc.datasrc import DataSourceClient
from socketserver import *
import os
from isc.config.ccsession import *
......@@ -97,6 +97,38 @@ TSIG_SIGN_EVERY_NTH = 96
XFROUT_MAX_MESSAGE_SIZE = 65535
# borrowed from xfrin.py @ #1298. We should eventually unify it.
def format_zone_str(zone_name, zone_class):
"""Helper function to format a zone name and class as a string of
the form '<name>/<class>'.
Parameters:
zone_name (isc.dns.Name) name to format
zone_class (isc.dns.RRClass) class to format
"""
return zone_name.to_text() + '/' + str(zone_class)
# borrowed from xfrin.py @ #1298.
def format_addrinfo(addrinfo):
"""Helper function to format the addrinfo as a string of the form
<addr>:<port> (for IPv4) or [<addr>]:port (for IPv6). For unix domain
sockets, and unknown address families, it returns a basic string
conversion of the third element of the passed tuple.
Parameters:
addrinfo: a 3-tuple consisting of address family, socket type, and,
depending on the family, either a 2-tuple with the address
and port, or a filename
"""
try:
if addrinfo[0] == socket.AF_INET:
return str(addrinfo[2][0]) + ":" + str(addrinfo[2][1])
elif addrinfo[0] == socket.AF_INET6:
return "[" + str(addrinfo[2][0]) + "]:" + str(addrinfo[2][1])
else:
return str(addrinfo[2])
except IndexError:
raise TypeError("addrinfo argument to format_addrinfo() does not "
"appear to be consisting of (family, socktype, (addr, port))")
def get_rrset_len(rrset):
"""Returns the wire length of the given RRset"""
bytes = bytearray()
......@@ -106,7 +138,7 @@ def get_rrset_len(rrset):
class XfroutSession():
def __init__(self, sock_fd, request_data, server, tsig_key_ring, remote,
default_acl, zone_config):
default_acl, zone_config, client_class=DataSourceClient):
self._sock_fd = sock_fd
self._request_data = request_data
self._server = server
......@@ -114,23 +146,51 @@ class XfroutSession():
self._tsig_ctx = None
self._tsig_len = 0
self._remote = remote
self._request_type = 'AXFR' # could be IXFR when we support it
self._acl = default_acl
self._zone_config = zone_config
self.handle()
self.ClientClass = client_class # parameterize this for testing
self._soa = None # will be set in _check_xfrout_available or in tests
self._handle()
def create_tsig_ctx(self, tsig_record, tsig_key_ring):
return TSIGContext(tsig_record.get_name(), tsig_record.get_rdata().get_algorithm(),
tsig_key_ring)
def handle(self):
''' Handle a xfrout query, send xfrout response '''
def _handle(self):
''' Handle a xfrout query, send xfrout response(s).
This is separated from the constructor so that we can override
it from tests.
'''
# Check the xfrout quota. We do both increase/decrease in this
# method so it's clear we always release it once acuired.
quota_ok = self._server.increase_transfers_counter()
ex = None
try:
self.dns_xfrout_start(self._sock_fd, self._request_data)
#TODO, avoid catching all exceptions
self.dns_xfrout_start(self._sock_fd, self._request_data, quota_ok)
except Exception as e:
logger.error(XFROUT_HANDLE_QUERY_ERROR, e)
pass
# To avoid resource leak we need catch all possible exceptions
# We log it later to exclude the case where even logger raises
# an exception.
ex = e
# Release any critical resources
if quota_ok:
self._server.decrease_transfers_counter()
self._close_socket()
if ex is not None:
logger.error(XFROUT_HANDLE_QUERY_ERROR, ex)
def _close_socket(self):
'''Simply close the socket via the given FD.
This is a dedicated subroutine of handle() and is sepsarated from it
for the convenience of tests.
'''
os.close(self._sock_fd)
def _check_request_tsig(self, msg, request_data):
......@@ -157,23 +217,31 @@ class XfroutSession():
# TSIG related checks
rcode = self._check_request_tsig(msg, mdata)
if rcode == Rcode.NOERROR():
# ACL checks
zone_name = msg.get_question()[0].get_name()
zone_class = msg.get_question()[0].get_class()
acl = self._get_transfer_acl(zone_name, zone_class)
acl_result = acl.execute(
isc.acl.dns.RequestContext(self._remote,
msg.get_tsig_record()))
if acl_result == DROP:
logger.info(XFROUT_QUERY_DROPPED, zone_name, zone_class,
self._remote[0], self._remote[1])
return None, None
elif acl_result == REJECT:
logger.info(XFROUT_QUERY_REJECTED, zone_name, zone_class,
self._remote[0], self._remote[1])
return Rcode.REFUSED(), msg
if rcode != Rcode.NOERROR():
return rcode, msg
# Make sure the question is valid. This should be ensured by
# the auth server, but since it's far from our xfrout itself,
# we check it by ourselves.
if msg.get_rr_count(Message.SECTION_QUESTION) != 1:
return Rcode.FORMERR(), msg
# ACL checks
zone_name = msg.get_question()[0].get_name()
zone_class = msg.get_question()[0].get_class()
acl = self._get_transfer_acl(zone_name, zone_class)
acl_result = acl.execute(
isc.acl.dns.RequestContext(self._remote[2], msg.get_tsig_record()))
if acl_result == DROP:
logger.info(XFROUT_QUERY_DROPPED, self._request_type,
format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
return None, None
elif acl_result == REJECT:
logger.info(XFROUT_QUERY_REJECTED, self._request_type,
format_addrinfo(self._remote),
format_zone_str(zone_name, zone_class))
return Rcode.REFUSED(), msg
return rcode, msg
......@@ -195,14 +263,6 @@ class XfroutSession():
return self._zone_config[config_key]['transfer_acl']
return self._acl
def _get_query_zone_name(self, msg):
question = msg.get_question()[0]
return question.get_name().to_text()
def _get_query_zone_class(self, msg):
question = msg.get_question()[0]
return question.get_class().to_text()
def _send_data(self, sock_fd, data):
size = len(data)
total_count = 0
......@@ -238,51 +298,49 @@ class XfroutSession():
msg.set_rcode(rcode_)
self._send_message(sock_fd, msg, self._tsig_ctx)
def _zone_has_soa(self, zone):
'''Judge if the zone has an SOA record.'''
# In some sense, the SOA defines a zone.
# If the current name server has authority for the
# specific zone, we need to judge if the zone has an SOA record;
# if not, we consider the zone has incomplete data, so xfrout can't
# serve for it.
if sqlite3_ds.get_zone_soa(zone, self._server.get_db_file()):
return True
return False
def _zone_exist(self, zonename):
'''Judge if the zone is configured by config manager.'''
# Currently, if we find the zone in datasource successfully, we
# consider the zone is configured, and the current name server has
# authority for the specific zone.
# TODO: should get zone's configuration from cfgmgr or other place
# in future.
return sqlite3_ds.zone_exist(zonename, self._server.get_db_file())
def _check_xfrout_available(self, zone_name):
'''Check if xfr request can be responsed.
TODO, Get zone's configuration from cfgmgr or some other place
eg. check allow_transfer setting,
'''
# If the current name server does not have authority for the
# zone, xfrout can't serve for it, return rcode NOTAUTH.
if not self._zone_exist(zone_name):
# Identify the data source for the requested zone and see if it has
# SOA while initializing objects used for request processing later.
# We should eventually generalize this so that we can choose the
# appropriate data source from (possible) multiple candidates.
# We should eventually take into account the RR class here.
# For now, we hardcode a particular type (SQLite3-based), and only
# consider that one.
datasrc_config = '{ "database_file": "' + \
self._server.get_db_file() + '"}'
self._datasrc_client = self.ClientClass('sqlite3', datasrc_config)
try:
# Note that we disable 'adjust_ttl'. In xfr-out we need to
# preserve as many things as possible (even if it's half broken)
# stored in the zone.
self._iterator = self._datasrc_client.get_iterator(zone_name,
False)
except isc.datasrc.Error:
# If the current name server does not have authority for the
# zone, xfrout can't serve for it, return rcode NOTAUTH.
# Note: this exception can happen for other reasons. We should
# update get_iterator() API so that we can distinguish "no such
# zone" and other cases (#1373). For now we consider all these
# cases as NOTAUTH.
return Rcode.NOTAUTH()
# If we are an authoritative name server for the zone, but fail
# to find the zone's SOA record in datasource, xfrout can't
# provide zone transfer for it.
if not self._zone_has_soa(zone_name):
self._soa = self._iterator.get_soa()
if self._soa is None or self._soa.get_rdata_count() != 1:
return Rcode.SERVFAIL()
#TODO, check allow_transfer
if not self._server.increase_transfers_counter():
return Rcode.REFUSED()
return Rcode.NOERROR()
def dns_xfrout_start(self, sock_fd, msg_query):
def dns_xfrout_start(self, sock_fd, msg_query, quota_ok=True):
rcode_, msg = self._parse_query_message(msg_query)
#TODO. create query message and parse header
if rcode_ is None: # Dropped by ACL
......@@ -292,29 +350,40 @@ class XfroutSession():
elif rcode_ != Rcode.NOERROR():
return self._reply_query_with_error_rcode(msg, sock_fd,
Rcode.FORMERR())
elif not quota_ok:
logger.warn(XFROUT_QUERY_QUOTA_EXCCEEDED, self._request_type,
format_addrinfo(self._remote),
self._server._max_transfers_out)
return self._reply_query_with_error_rcode(msg, sock_fd,
Rcode.REFUSED())
zone_name = self._get_query_zone_name(msg)
zone_class_str = self._get_query_zone_class(msg)
# TODO: should we not also include class in the check?
rcode_ = self._check_xfrout_available(zone_name)
question = msg.get_question()[0]
zone_name = question.get_name()
zone_class = question.get_class()
zone_str = format_zone_str(zone_name, zone_class) # for logging
# TODO: we should also include class in the check
try:
rcode_ = self._check_xfrout_available(zone_name)
except Exception as ex:
logger.error(XFROUT_XFR_TRANSFER_CHECK_ERROR, self._request_type,
format_addrinfo(self._remote), zone_str, ex)
rcode_ = Rcode.SERVFAIL()
if rcode_ != Rcode.NOERROR():
logger.info(XFROUT_AXFR_TRANSFER_FAILED, zone_name,
zone_class_str, rcode_.to_text())
logger.info(XFROUT_AXFR_TRANSFER_FAILED, self._request_type,
format_addrinfo(self._remote), zone_str, rcode_)
return self._reply_query_with_error_rcode(msg, sock_fd, rcode_)
try:
logger.info(XFROUT_AXFR_TRANSFER_STARTED, zone_name, zone_class_str)
self._reply_xfrout_query(msg, sock_fd, zone_name)
logger.info(XFROUT_AXFR_TRANSFER_STARTED, self._request_type,
format_addrinfo(self._remote), zone_str)
self._reply_xfrout_query(msg, sock_fd)
except Exception as err:
logger.error(XFROUT_AXFR_TRANSFER_ERROR, zone_name,
zone_class_str, str(err))
logger.error(XFROUT_AXFR_TRANSFER_ERROR, self._request_type,
format_addrinfo(self._remote), zone_str, err)
pass
logger.info(XFROUT_AXFR_TRANSFER_DONE, zone_name, zone_class_str)
self._server.decrease_transfers_counter()
return
logger.info(XFROUT_AXFR_TRANSFER_DONE, self._request_type,
format_addrinfo(self._remote), zone_str)
def _clear_message(self, msg):
qid = msg.get_qid()
......@@ -329,16 +398,6 @@ class XfroutSession():
msg.set_header_flag(Message.HEADERFLAG_QR)
return msg
def _create_rrset_from_db_record(self, record):
'''Create one rrset from one record of datasource, if the schema of record is changed,
This function should be updated first.
'''
rrtype_ = RRType(record[5])
rdata_ = Rdata(rrtype_, RRClass("IN"), " ".join(record[7:]))
rrset_ = RRset(Name(record[2]), RRClass("IN"), rrtype_, RRTTL( int(record[4])))
rrset_.add_rdata(rdata_)
return rrset_
def _send_message_with_last_soa(self, msg, sock_fd, rrset_soa, message_upper_len,
count_since_last_tsig_sign):
'''Add the SOA record to the end of message. If it can't be
......@@ -361,33 +420,30 @@ class XfroutSession():
self._send_message(sock_fd, msg, self._tsig_ctx)
def _reply_xfrout_query(self, msg, sock_fd, zone_name):
def _reply_xfrout_query(self, msg, sock_fd):
#TODO, there should be a better way to insert rrset.
count_since_last_tsig_sign = TSIG_SIGN_EVERY_NTH
msg.make_response()
msg.set_header_flag(Message.HEADERFLAG_AA)
soa_record = sqlite3_ds.get_zone_soa(zone_name, self._server.get_db_file())
rrset_soa = self._create_rrset_from_db_record(soa_record)
msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
msg.add_rrset(Message.SECTION_ANSWER, self._soa)
message_upper_len = get_rrset_len(rrset_soa) + self._tsig_len
message_upper_len = get_rrset_len(self._soa) + self._tsig_len
for rr_data in sqlite3_ds.get_zone_datas(zone_name, self._server.get_db_file()):
if self._server._shutdown_event.is_set(): # Check if xfrout is shutdown
for rrset in self._iterator:
# Check if xfrout is shutdown
if self._server._shutdown_event.is_set():
logger.info(XFROUT_STOPPING)
return
# TODO: RRType.SOA() ?
if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
continue
rrset_ = self._create_rrset_from_db_record(rr_data)
if rrset.get_type() == RRType.SOA():
continue
# We calculate the maximum size of the RRset (i.e. the
# size without compression) and use that to see if we
# may have reached the limit
rrset_len = get_rrset_len(rrset_)
rrset_len = get_rrset_len(rrset)
if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
msg.add_rrset(Message.SECTION_ANSWER, rrset_)
msg.add_rrset(Message.SECTION_ANSWER, rrset)
message_upper_len += rrset_len
continue
......@@ -400,7 +456,8 @@ class XfroutSession():
count_since_last_tsig_sign += 1
msg = self._clear_message(msg)
msg.add_rrset(Message.SECTION_ANSWER, rrset_) # Add the rrset to the new message
# Add the RRset to the new message
msg.add_rrset(Message.SECTION_ANSWER, rrset)
# Reserve tsig space for signed packet
if count_since_last_tsig_sign == TSIG_SIGN_EVERY_NTH:
......@@ -408,7 +465,8 @@ class XfroutSession():
else:
message_upper_len = rrset_len
self._send_message_with_last_soa(msg, sock_fd, rrset_soa, message_upper_len,
self._send_message_with_last_soa(msg, sock_fd, self._soa,
message_upper_len,
count_since_last_tsig_sign)
class UnixSockServer(socketserver_mixin.NoPollMixIn,
......@@ -517,9 +575,12 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
t.start()
def _guess_remote(self, sock_fd):
"""
Guess remote address and port of the socket. The sock_fd must be a
socket
"""Guess remote address and port of the socket.
The sock_fd must be a file descriptor of a socket.
This method retuns a 3-tuple consisting of address family,
socket type, and a 2-tuple with the address (string) and port (int).
"""
# This uses a trick. If the socket is IPv4 in reality and we pretend
# it to be IPv6, it returns IPv4 address anyway. This doesn't seem
......@@ -531,11 +592,23 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
# To make it work even on hosts without IPv6 support
# (Any idea how to simulate this in test?)
sock = socket.fromfd(sock_fd, socket.AF_INET, socket.SOCK_STREAM)
return sock.getpeername()
peer = sock.getpeername()
# Identify the correct socket family. Due to the above "trick",
# we cannot simply use sock.family.
family = socket.AF_INET6
try:
socket.inet_pton(socket.AF_INET6, peer[0])
except socket.error:
family = socket.AF_INET
return (family, socket.SOCK_STREAM, peer)
def finish_request(self, sock_fd, request_data):
'''Finish one request by instantiating RequestHandlerClass.
This is an entry point of a separate thread spawned in
UnixSockServer.process_request().
This method creates a XfroutSession object.
'''
self._lock.acquire()
......
......@@ -15,17 +15,24 @@
# No namespace declaration - these constants go in the global namespace
# of the xfrout messages python module.
% XFROUT_AXFR_TRANSFER_DONE transfer of %1/%2 complete
% XFROUT_AXFR_TRANSFER_DONE %1 client %2: transfer of %3 complete
The transfer of the given zone has been completed successfully, or was
aborted due to a shutdown event.
% XFROUT_AXFR_TRANSFER_ERROR error transferring zone %1/%2: %3
% XFROUT_AXFR_TRANSFER_ERROR %1 client %2: error transferring zone %3: %4
An uncaught exception was encountered while sending the response to
an AXFR query. The error message of the exception is included in the
log message, but this error most likely points to incomplete exception
handling in the code.
% XFROUT_AXFR_TRANSFER_FAILED transfer of %1/%2 failed, rcode: %3
% XFROUT_XFR_TRANSFER_CHECK_ERROR %1 client %2: check for transfer of %3 failed: %4
Pre-response check for an incomding XFR request failed unexpectedly.
The most likely cause of this is that some low level error in the data
source, but it may also be other general (more unlikely) errors such
as memory shortage. Some detail of the error is also included in the
message. The xfrout server tries to return a SERVFAIL response in this case.
% XFROUT_AXFR_TRANSFER_FAILED %1 client %2: transfer of %3 failed, rcode: %4
A transfer out for the given zone failed. An error response is sent
to the client. The given rcode is the rcode that is set in the error
response. This is either NOTAUTH (we are not authoritative for the
......@@ -36,7 +43,7 @@ Xfrout/max_transfers_out, has been reached).
# Still a TODO, but when implemented, REFUSED can also mean
# the client is not allowed to transfer the zone
% XFROUT_AXFR_TRANSFER_STARTED transfer of zone %1/%2 has started
% XFROUT_AXFR_TRANSFER_STARTED %1 client %2: transfer of zone %3 has started
A transfer out of the given zone has started.
% XFROUT_BAD_TSIG_KEY_STRING bad TSIG key string: %1
......@@ -106,16 +113,27 @@ in the log message, but at this point no specific information other
than that could be given. This points to incomplete exception handling
in the code.
% XFROUT_QUERY_DROPPED request to transfer %1/%2 to [%3]:%4 dropped
The xfrout process silently dropped a request to transfer zone to given host.
This is required by the ACLs. The %1 and %2 represent the zone name and class,
the %3 and %4 the IP address and port of the peer requesting the transfer.
% XFROUT_QUERY_DROPPED %1 client %2: request to transfer %3 dropped
The xfrout process silently dropped a request to transfer zone to
given host. This is required by the ACLs. The %2 represents the IP
address and port of the peer requesting the transfer, and the %3
represents the zone name and class.
% XFROUT_QUERY_REJECTED request to transfer %1/%2 to [%3]:%4 rejected
% XFROUT_QUERY_REJECTED %1 client %2: request to transfer %3 rejected
The xfrout process rejected (by REFUSED rcode) a request to transfer zone to
given host. This is because of ACLs. The %1 and %2 represent the zone name and
class, the %3 and %4 the IP address and port of the peer requesting the
transfer.
given host. This is because of ACLs. The %2 represents the IP
address and port of the peer requesting the transfer, and the %3
represents the zone name and class.