|
@@ -504,6 +504,25 @@ class XfrinConnection(asyncore.dispatcher):
|
|
|
logger.error(XFRIN_CONNECT_MASTER, self._master_address, str(e))
|
|
|
return False
|
|
|
|
|
|
+ def _get_zone_soa(self):
|
|
|
+ result, finder = self._datasrc_client.find_zone(self._zone_name)
|
|
|
+ if result != DataSourceClient.SUCCESS:
|
|
|
+ raise XfrinException('Zone not found in the given data ' +
|
|
|
+ 'source: ' + self.zone_str())
|
|
|
+ result, soa_rrset = finder.find(self._zone_name, RRType.SOA(),
|
|
|
+ None, ZoneFinder.FIND_DEFAULT)
|
|
|
+ if result != ZoneFinder.SUCCESS:
|
|
|
+ raise XfrinException('SOA RR not found in zone: ' +
|
|
|
+ self.zone_str())
|
|
|
+ # Especially for database-based zones, a working zone may be in
|
|
|
+ # a broken state where it has more than one SOA RR. We proactively
|
|
|
+ # check the condition and abort the xfr attempt if we identify it.
|
|
|
+ if soa_rrset.get_rdata_count() != 1:
|
|
|
+ raise XfrinException('Invalid number of SOA RRs for ' +
|
|
|
+ self.zone_str() + ': ' +
|
|
|
+ str(soa_rrset.get_rdata_count()))
|
|
|
+ return soa_rrset
|
|
|
+
|
|
|
def _create_query(self, query_type):
|
|
|
'''Create an XFR-related query message.
|
|
|
|
|
@@ -528,24 +547,24 @@ class XfrinConnection(asyncore.dispatcher):
|
|
|
if query_type == RRType.IXFR():
|
|
|
# get the zone finder. this must be SUCCESS (not even
|
|
|
# PARTIALMATCH) because we are specifying the zone origin name.
|
|
|
- result, finder = self._datasrc_client.find_zone(self._zone_name)
|
|
|
- if result != DataSourceClient.SUCCESS:
|
|
|
- raise XfrinException('Zone not found in the given data ' +
|
|
|
- 'source: ' + self.zone_str())
|
|
|
- result, soa_rrset = finder.find(self._zone_name, RRType.SOA(),
|
|
|
- None, ZoneFinder.FIND_DEFAULT)
|
|
|
- if result != ZoneFinder.SUCCESS:
|
|
|
- raise XfrinException('SOA RR not found in zone: ' +
|
|
|
- self.zone_str())
|
|
|
- # Especially for database-based zones, a working zone may be in
|
|
|
- # a broken state where it has more than one SOA RR. We proactively
|
|
|
- # check the condition and abort the xfr attempt if we identify it.
|
|
|
- if soa_rrset.get_rdata_count() != 1:
|
|
|
- raise XfrinException('Invalid number of SOA RRs for ' +
|
|
|
- self.zone_str() + ': ' +
|
|
|
- str(soa_rrset.get_rdata_count()))
|
|
|
- msg.add_rrset(Message.SECTION_AUTHORITY, soa_rrset)
|
|
|
- self._request_serial = get_soa_serial(soa_rrset.get_rdata()[0])
|
|
|
+ zone_soa_rr = self._get_zone_soa()
|
|
|
+ msg.add_rrset(Message.SECTION_AUTHORITY, zone_soa_rr)
|
|
|
+ self._request_serial = get_soa_serial(zone_soa_rr.get_rdata()[0])
|
|
|
+ else:
|
|
|
+ # For AXFR, we temporarily provide backward compatible behavior
|
|
|
+ # where xfrin is responsible for creating zone in the corresponding
|
|
|
+ # DB table. Note that the code below uses the old data source
|
|
|
+ # API and assumes SQLite3 in an ugly manner. We'll have to
|
|
|
+ # develop a better way of managing zones in a generic way and
|
|
|
+ # eliminate the code like the one here.
|
|
|
+ try:
|
|
|
+ self._get_zone_soa()
|
|
|
+ except XfrinException:
|
|
|
+ def empty_rr_generator():
|
|
|
+ return []
|
|
|
+ isc.datasrc.sqlite3_ds.load(self._db_file,
|
|
|
+ self._zone_name.to_text(),
|
|
|
+ empty_rr_generator)
|
|
|
return msg
|
|
|
|
|
|
def _send_data(self, data):
|
|
@@ -803,6 +822,9 @@ def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
|
|
|
sock_map = {}
|
|
|
conn = XfrinConnection(sock_map, zone_name, rrclass, datasrc_client,
|
|
|
shutdown_event, master_addrinfo, tsig_key)
|
|
|
+ # XXX: We still need _db_file for temporary workaround in _create_query().
|
|
|
+ # This should be removed when we eliminate the need for the workaround.
|
|
|
+ conn._db_file = db_file
|
|
|
ret = XFRIN_FAIL
|
|
|
if conn.connect_to_master():
|
|
|
ret = conn.do_xfrin(check_soa, request_type)
|