xfrout_test.py.in 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. # Copyright (C) 2010 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. '''Tests for the XfroutSession and UnixSockServer classes '''
  16. import unittest
  17. import os
  18. from isc.testutils.tsigctx_mock import MockTSIGContext
  19. from isc.cc.session import *
  20. from pydnspp import *
  21. from xfrout import *
  22. import xfrout
  23. TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
  24. # our fake socket, where we can read and insert messages
  25. class MySocket():
  26. def __init__(self, family, type):
  27. self.family = family
  28. self.type = type
  29. self.sendqueue = bytearray()
  30. def connect(self, to):
  31. pass
  32. def close(self):
  33. pass
  34. def send(self, data):
  35. self.sendqueue.extend(data);
  36. return len(data)
  37. def readsent(self):
  38. if len(self.sendqueue) >= 2:
  39. size = 2 + struct.unpack("!H", self.sendqueue[:2])[0]
  40. else:
  41. size = 0
  42. result = self.sendqueue[:size]
  43. self.sendqueue = self.sendqueue[size:]
  44. return result
  45. def read_msg(self):
  46. sent_data = self.readsent()
  47. get_msg = Message(Message.PARSE)
  48. get_msg.from_wire(bytes(sent_data[2:]))
  49. return get_msg
  50. def clear_send(self):
  51. del self.sendqueue[:]
  52. # We subclass the Session class we're testing here, only
  53. # to override the handle() and _send_data() method
  54. class MyXfroutSession(XfroutSession):
  55. def handle(self):
  56. pass
  57. def _send_data(self, sock, data):
  58. size = len(data)
  59. total_count = 0
  60. while total_count < size:
  61. count = sock.send(data[total_count:])
  62. total_count += count
  63. class Dbserver:
  64. def __init__(self):
  65. self._shutdown_event = threading.Event()
  66. def get_db_file(self):
  67. return None
  68. def decrease_transfers_counter(self):
  69. pass
  70. class TestXfroutSession(unittest.TestCase):
  71. def getmsg(self):
  72. msg = Message(Message.PARSE)
  73. msg.from_wire(self.mdata)
  74. return msg
  75. def create_mock_tsig_ctx(self, error):
  76. # This helper function creates a MockTSIGContext for a given key
  77. # and TSIG error to be used as a result of verify (normally faked
  78. # one)
  79. mock_ctx = MockTSIGContext(TSIG_KEY)
  80. mock_ctx.error = error
  81. return mock_ctx
  82. def message_has_tsig(self, msg):
  83. return msg.get_tsig_record() is not None
  84. def create_request_data_with_tsig(self):
  85. msg = Message(Message.RENDER)
  86. query_id = 0x1035
  87. msg.set_qid(query_id)
  88. msg.set_opcode(Opcode.QUERY())
  89. msg.set_rcode(Rcode.NOERROR())
  90. query_question = Question(Name("example.com."), RRClass.IN(), RRType.AXFR())
  91. msg.add_question(query_question)
  92. renderer = MessageRenderer()
  93. tsig_ctx = MockTSIGContext(TSIG_KEY)
  94. msg.to_wire(renderer, tsig_ctx)
  95. reply_data = renderer.get_data()
  96. return reply_data
  97. def setUp(self):
  98. self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
  99. #self.log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
  100. self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), TSIGKeyRing())
  101. self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
  102. self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
  103. def test_parse_query_message(self):
  104. [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
  105. self.assertEqual(get_rcode.to_text(), "NOERROR")
  106. # tsig signed query message
  107. request_data = self.create_request_data_with_tsig()
  108. # BADKEY
  109. [rcode, msg] = self.xfrsess._parse_query_message(request_data)
  110. self.assertEqual(rcode.to_text(), "NOTAUTH")
  111. self.assertTrue(self.xfrsess._tsig_ctx is not None)
  112. # NOERROR
  113. self.xfrsess._tsig_key_ring.add(TSIG_KEY)
  114. [rcode, msg] = self.xfrsess._parse_query_message(request_data)
  115. self.assertEqual(rcode.to_text(), "NOERROR")
  116. self.assertTrue(self.xfrsess._tsig_ctx is not None)
  117. def test_get_query_zone_name(self):
  118. msg = self.getmsg()
  119. self.assertEqual(self.xfrsess._get_query_zone_name(msg), "example.com.")
  120. def test_send_data(self):
  121. self.xfrsess._send_data(self.sock, self.mdata)
  122. senddata = self.sock.readsent()
  123. self.assertEqual(senddata, self.mdata)
  124. def test_reply_xfrout_query_with_error_rcode(self):
  125. msg = self.getmsg()
  126. self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
  127. get_msg = self.sock.read_msg()
  128. self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
  129. # tsig signed message
  130. msg = self.getmsg()
  131. self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
  132. self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
  133. get_msg = self.sock.read_msg()
  134. self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
  135. self.assertTrue(self.message_has_tsig(get_msg))
  136. def test_send_message(self):
  137. msg = self.getmsg()
  138. msg.make_response()
  139. # soa record data with different cases
  140. soa_record = (4, 3, 'Example.com.', 'com.Example.', 3600, 'SOA', None, 'master.Example.com. admin.exAmple.com. 1234 3600 1800 2419200 7200')
  141. rrset_soa = self.xfrsess._create_rrset_from_db_record(soa_record)
  142. msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
  143. self.xfrsess._send_message(self.sock, msg)
  144. send_out_data = self.sock.readsent()[2:]
  145. # CASE_INSENSITIVE compression mode
  146. render = MessageRenderer();
  147. render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
  148. msg.to_wire(render)
  149. self.assertNotEqual(render.get_data(), send_out_data)
  150. # CASE_SENSITIVE compression mode
  151. render.clear()
  152. render.set_compress_mode(MessageRenderer.CASE_SENSITIVE)
  153. render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
  154. msg.to_wire(render)
  155. self.assertEqual(render.get_data(), send_out_data)
  156. def test_clear_message(self):
  157. msg = self.getmsg()
  158. qid = msg.get_qid()
  159. opcode = msg.get_opcode()
  160. rcode = msg.get_rcode()
  161. self.xfrsess._clear_message(msg)
  162. self.assertEqual(msg.get_qid(), qid)
  163. self.assertEqual(msg.get_opcode(), opcode)
  164. self.assertEqual(msg.get_rcode(), rcode)
  165. self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_AA))
  166. def test_reply_query_with_format_error(self):
  167. msg = self.getmsg()
  168. self.xfrsess._reply_query_with_format_error(msg, self.sock)
  169. get_msg = self.sock.read_msg()
  170. self.assertEqual(get_msg.get_rcode().to_text(), "FORMERR")
  171. # tsig signed message
  172. msg = self.getmsg()
  173. self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
  174. self.xfrsess._reply_query_with_format_error(msg, self.sock)
  175. get_msg = self.sock.read_msg()
  176. self.assertEqual(get_msg.get_rcode().to_text(), "FORMERR")
  177. self.assertTrue(self.message_has_tsig(get_msg))
  178. def test_create_rrset_from_db_record(self):
  179. rrset = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  180. self.assertEqual(rrset.get_name().to_text(), "example.com.")
  181. self.assertEqual(rrset.get_class(), RRClass("IN"))
  182. self.assertEqual(rrset.get_type().to_text(), "SOA")
  183. rdata = rrset.get_rdata()
  184. self.assertEqual(rdata[0].to_text(), self.soa_record[7])
  185. def test_send_message_with_last_soa(self):
  186. rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  187. msg = self.getmsg()
  188. msg.make_response()
  189. # packet number less than TSIG_SIGN_EVERY_NTH
  190. packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
  191. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa,
  192. 0, packet_neet_not_sign)
  193. get_msg = self.sock.read_msg()
  194. # tsig context is not exist
  195. self.assertFalse(self.message_has_tsig(get_msg))
  196. self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
  197. self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
  198. self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
  199. #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
  200. answer = get_msg.get_section(Message.SECTION_ANSWER)[0]#answer_rrset_iter.get_rrset()
  201. self.assertEqual(answer.get_name().to_text(), "example.com.")
  202. self.assertEqual(answer.get_class(), RRClass("IN"))
  203. self.assertEqual(answer.get_type().to_text(), "SOA")
  204. rdata = answer.get_rdata()
  205. self.assertEqual(rdata[0].to_text(), self.soa_record[7])
  206. # msg is the TSIG_SIGN_EVERY_NTH one
  207. # sending the message with last soa together
  208. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa,
  209. 0, TSIG_SIGN_EVERY_NTH)
  210. get_msg = self.sock.read_msg()
  211. # tsig context is not exist
  212. self.assertFalse(self.message_has_tsig(get_msg))
  213. def test_send_message_with_last_soa_with_tsig(self):
  214. # create tsig context
  215. self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
  216. rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  217. msg = self.getmsg()
  218. msg.make_response()
  219. # packet number less than TSIG_SIGN_EVERY_NTH
  220. packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
  221. # msg is not the TSIG_SIGN_EVERY_NTH one
  222. # sending the message with last soa together
  223. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa,
  224. 0, packet_neet_not_sign)
  225. get_msg = self.sock.read_msg()
  226. self.assertTrue(self.message_has_tsig(get_msg))
  227. self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
  228. self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
  229. self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
  230. # msg is the TSIG_SIGN_EVERY_NTH one
  231. # sending the message with last soa together
  232. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa,
  233. 0, TSIG_SIGN_EVERY_NTH)
  234. get_msg = self.sock.read_msg()
  235. self.assertTrue(self.message_has_tsig(get_msg))
  236. def test_trigger_send_message_with_last_soa(self):
  237. rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
  238. rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
  239. rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  240. msg = self.getmsg()
  241. msg.make_response()
  242. msg.add_rrset(Message.SECTION_ANSWER, rrset_a)
  243. # length larger than MAX-len(rrset)
  244. length_need_split = xfrout.XFROUT_MAX_MESSAGE_SIZE - get_rrset_len(rrset_soa) + 1
  245. # packet number less than TSIG_SIGN_EVERY_NTH
  246. packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
  247. # give the function a value that is larger than MAX-len(rrset)
  248. # this should have triggered the sending of two messages
  249. # (1 with the rrset we added manually, and 1 that triggered
  250. # the sending in _with_last_soa)
  251. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, length_need_split,
  252. packet_neet_not_sign)
  253. get_msg = self.sock.read_msg()
  254. self.assertFalse(self.message_has_tsig(get_msg))
  255. self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
  256. self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
  257. self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
  258. answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
  259. self.assertEqual(answer.get_name().to_text(), "example.com.")
  260. self.assertEqual(answer.get_class(), RRClass("IN"))
  261. self.assertEqual(answer.get_type().to_text(), "A")
  262. rdata = answer.get_rdata()
  263. self.assertEqual(rdata[0].to_text(), "192.0.2.1")
  264. get_msg = self.sock.read_msg()
  265. self.assertFalse(self.message_has_tsig(get_msg))
  266. self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 0)
  267. self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
  268. self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
  269. #answer_rrset_iter = section_iter(get_msg, Message.SECTION_ANSWER)
  270. answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
  271. self.assertEqual(answer.get_name().to_text(), "example.com.")
  272. self.assertEqual(answer.get_class(), RRClass("IN"))
  273. self.assertEqual(answer.get_type().to_text(), "SOA")
  274. rdata = answer.get_rdata()
  275. self.assertEqual(rdata[0].to_text(), self.soa_record[7])
  276. # and it should not have sent anything else
  277. self.assertEqual(0, len(self.sock.sendqueue))
  278. def test_trigger_send_message_with_last_soa_with_tsig(self):
  279. self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
  280. rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  281. msg = self.getmsg()
  282. msg.make_response()
  283. msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
  284. # length larger than MAX-len(rrset)
  285. length_need_split = xfrout.XFROUT_MAX_MESSAGE_SIZE - get_rrset_len(rrset_soa) + 1
  286. # packet number less than TSIG_SIGN_EVERY_NTH
  287. packet_neet_not_sign = xfrout.TSIG_SIGN_EVERY_NTH - 1
  288. # give the function a value that is larger than MAX-len(rrset)
  289. # this should have triggered the sending of two messages
  290. # (1 with the rrset we added manually, and 1 that triggered
  291. # the sending in _with_last_soa)
  292. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, length_need_split,
  293. packet_neet_not_sign)
  294. get_msg = self.sock.read_msg()
  295. # msg is not the TSIG_SIGN_EVERY_NTH one, it shouldn't be tsig signed
  296. self.assertFalse(self.message_has_tsig(get_msg))
  297. # the last packet should be tsig signed
  298. get_msg = self.sock.read_msg()
  299. self.assertTrue(self.message_has_tsig(get_msg))
  300. # and it should not have sent anything else
  301. self.assertEqual(0, len(self.sock.sendqueue))
  302. # msg is the TSIG_SIGN_EVERY_NTH one, it should be tsig signed
  303. self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, length_need_split,
  304. xfrout.TSIG_SIGN_EVERY_NTH)
  305. get_msg = self.sock.read_msg()
  306. self.assertTrue(self.message_has_tsig(get_msg))
  307. # the last packet should be tsig signed
  308. get_msg = self.sock.read_msg()
  309. self.assertTrue(self.message_has_tsig(get_msg))
  310. # and it should not have sent anything else
  311. self.assertEqual(0, len(self.sock.sendqueue))
  312. def test_get_rrset_len(self):
  313. rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
  314. self.assertEqual(82, get_rrset_len(rrset_soa))
  315. def test_zone_has_soa(self):
  316. global sqlite3_ds
  317. def mydb1(zone, file):
  318. return True
  319. sqlite3_ds.get_zone_soa = mydb1
  320. self.assertTrue(self.xfrsess._zone_has_soa(""))
  321. def mydb2(zone, file):
  322. return False
  323. sqlite3_ds.get_zone_soa = mydb2
  324. self.assertFalse(self.xfrsess._zone_has_soa(""))
  325. def test_zone_exist(self):
  326. global sqlite3_ds
  327. def zone_exist(zone, file):
  328. return zone
  329. sqlite3_ds.zone_exist = zone_exist
  330. self.assertTrue(self.xfrsess._zone_exist(True))
  331. self.assertFalse(self.xfrsess._zone_exist(False))
  332. def test_check_xfrout_available(self):
  333. def zone_exist(zone):
  334. return zone
  335. def zone_has_soa(zone):
  336. return (not zone)
  337. self.xfrsess._zone_exist = zone_exist
  338. self.xfrsess._zone_has_soa = zone_has_soa
  339. self.assertEqual(self.xfrsess._check_xfrout_available(False).to_text(), "NOTAUTH")
  340. self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "SERVFAIL")
  341. def zone_empty(zone):
  342. return zone
  343. self.xfrsess._zone_has_soa = zone_empty
  344. def false_func():
  345. return False
  346. self.xfrsess._server.increase_transfers_counter = false_func
  347. self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "REFUSED")
  348. def true_func():
  349. return True
  350. self.xfrsess._server.increase_transfers_counter = true_func
  351. self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "NOERROR")
  352. def test_dns_xfrout_start_formerror(self):
  353. # formerror
  354. self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
  355. sent_data = self.sock.readsent()
  356. self.assertEqual(len(sent_data), 0)
  357. def default(self, param):
  358. return "example.com"
  359. def test_dns_xfrout_start_notauth(self):
  360. self.xfrsess._get_query_zone_name = self.default
  361. def notauth(formpara):
  362. return Rcode.NOTAUTH()
  363. self.xfrsess._check_xfrout_available = notauth
  364. self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
  365. get_msg = self.sock.read_msg()
  366. self.assertEqual(get_msg.get_rcode().to_text(), "NOTAUTH")
  367. def test_dns_xfrout_start_noerror(self):
  368. self.xfrsess._get_query_zone_name = self.default
  369. def noerror(form):
  370. return Rcode.NOERROR()
  371. self.xfrsess._check_xfrout_available = noerror
  372. def myreply(msg, sock, zonename):
  373. self.sock.send(b"success")
  374. self.xfrsess._reply_xfrout_query = myreply
  375. self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
  376. self.assertEqual(self.sock.readsent(), b"success")
  377. def test_reply_xfrout_query_noerror(self):
  378. global sqlite3_ds
  379. def get_zone_soa(zonename, file):
  380. return self.soa_record
  381. def get_zone_datas(zone, file):
  382. return [self.soa_record]
  383. sqlite3_ds.get_zone_soa = get_zone_soa
  384. sqlite3_ds.get_zone_datas = get_zone_datas
  385. self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
  386. reply_msg = self.sock.read_msg()
  387. self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
  388. def test_reply_xfrout_query_noerror_with_tsig(self):
  389. rrset_data = (4, 3, 'a.example.com.', 'com.example.', 3600, 'A', None, '192.168.1.1')
  390. global sqlite3_ds
  391. global xfrout
  392. def get_zone_soa(zonename, file):
  393. return self.soa_record
  394. def get_zone_datas(zone, file):
  395. zone_rrsets = []
  396. for i in range(0, 100):
  397. zone_rrsets.insert(i, rrset_data)
  398. return zone_rrsets
  399. def get_rrset_len(rrset):
  400. return 65520
  401. sqlite3_ds.get_zone_soa = get_zone_soa
  402. sqlite3_ds.get_zone_datas = get_zone_datas
  403. xfrout.get_rrset_len = get_rrset_len
  404. self.xfrsess._tsig_ctx = self.create_mock_tsig_ctx(TSIGError.NOERROR)
  405. self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
  406. # tsig signed first package
  407. reply_msg = self.sock.read_msg()
  408. self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 1)
  409. self.assertTrue(self.message_has_tsig(reply_msg))
  410. # (TSIG_SIGN_EVERY_NTH - 1) packets have no tsig
  411. for i in range(0, xfrout.TSIG_SIGN_EVERY_NTH - 1):
  412. reply_msg = self.sock.read_msg()
  413. self.assertFalse(self.message_has_tsig(reply_msg))
  414. # TSIG_SIGN_EVERY_NTH packet has tsig
  415. reply_msg = self.sock.read_msg()
  416. self.assertTrue(self.message_has_tsig(reply_msg))
  417. for i in range(0, 100 - TSIG_SIGN_EVERY_NTH):
  418. reply_msg = self.sock.read_msg()
  419. self.assertFalse(self.message_has_tsig(reply_msg))
  420. # tsig signed last package
  421. reply_msg = self.sock.read_msg()
  422. self.assertTrue(self.message_has_tsig(reply_msg))
  423. # and it should not have sent anything else
  424. self.assertEqual(0, len(self.sock.sendqueue))
  425. class MyCCSession():
  426. def __init__(self):
  427. pass
  428. def get_remote_config_value(self, module_name, identifier):
  429. if module_name == "Auth" and identifier == "database_file":
  430. return "initdb.file", False
  431. else:
  432. return "unknown", False
  433. class MyUnixSockServer(UnixSockServer):
  434. def __init__(self):
  435. self._lock = threading.Lock()
  436. self._transfers_counter = 0
  437. self._shutdown_event = threading.Event()
  438. self._max_transfers_out = 10
  439. self._cc = MyCCSession()
  440. #self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
  441. class TestUnixSockServer(unittest.TestCase):
  442. def setUp(self):
  443. self.write_sock, self.read_sock = socket.socketpair()
  444. self.unix = MyUnixSockServer()
  445. def test_receive_query_message(self):
  446. send_msg = b"\xd6=\x00\x00\x00\x01\x00"
  447. msg_len = struct.pack('H', socket.htons(len(send_msg)))
  448. self.write_sock.send(msg_len)
  449. self.write_sock.send(send_msg)
  450. recv_msg = self.unix._receive_query_message(self.read_sock)
  451. self.assertEqual(recv_msg, send_msg)
  452. def test_updata_config_data(self):
  453. tsig_key_str = 'example.com:SFuWd/q99SzF8Yzd1QbB9g=='
  454. tsig_key_list = [tsig_key_str]
  455. bad_key_list = ['bad..example.com:SFuWd/q99SzF8Yzd1QbB9g==']
  456. self.unix.update_config_data({'transfers_out':10 })
  457. self.assertEqual(self.unix._max_transfers_out, 10)
  458. self.assertTrue(self.unix.tsig_key_ring is not None)
  459. self.unix.update_config_data({'transfers_out':9, 'tsig_key_ring':tsig_key_list})
  460. self.assertEqual(self.unix._max_transfers_out, 9)
  461. self.assertEqual(self.unix.tsig_key_ring.size(), 1)
  462. self.unix.tsig_key_ring.remove(Name("example.com."))
  463. self.assertEqual(self.unix.tsig_key_ring.size(), 0)
  464. # bad tsig key
  465. config_data = {'transfers_out':9, 'tsig_key_ring': bad_key_list}
  466. self.assertRaises(None, self.unix.update_config_data(config_data))
  467. self.assertEqual(self.unix.tsig_key_ring.size(), 0)
  468. def test_get_db_file(self):
  469. self.assertEqual(self.unix.get_db_file(), "initdb.file")
  470. def test_increase_transfers_counter(self):
  471. self.unix._max_transfers_out = 10
  472. count = self.unix._transfers_counter
  473. self.assertEqual(self.unix.increase_transfers_counter(), True)
  474. self.assertEqual(count + 1, self.unix._transfers_counter)
  475. self.unix._max_transfers_out = 0
  476. count = self.unix._transfers_counter
  477. self.assertEqual(self.unix.increase_transfers_counter(), False)
  478. self.assertEqual(count, self.unix._transfers_counter)
  479. def test_decrease_transfers_counter(self):
  480. count = self.unix._transfers_counter
  481. self.unix.decrease_transfers_counter()
  482. self.assertEqual(count - 1, self.unix._transfers_counter)
  483. def _remove_file(self, sock_file):
  484. try:
  485. os.remove(sock_file)
  486. except OSError:
  487. pass
  488. def test_sock_file_in_use_file_exist(self):
  489. sock_file = 'temp.sock.file'
  490. self._remove_file(sock_file)
  491. self.assertFalse(self.unix._sock_file_in_use(sock_file))
  492. self.assertFalse(os.path.exists(sock_file))
  493. def test_sock_file_in_use_file_not_exist(self):
  494. self.assertFalse(self.unix._sock_file_in_use('temp.sock.file'))
  495. def _start_unix_sock_server(self, sock_file):
  496. serv = ThreadingUnixStreamServer(sock_file, BaseRequestHandler)
  497. serv_thread = threading.Thread(target=serv.serve_forever)
  498. serv_thread.setDaemon(True)
  499. serv_thread.start()
  500. def test_sock_file_in_use(self):
  501. sock_file = 'temp.sock.file'
  502. self._remove_file(sock_file)
  503. self.assertFalse(self.unix._sock_file_in_use(sock_file))
  504. self._start_unix_sock_server(sock_file)
  505. old_stdout = sys.stdout
  506. sys.stdout = open(os.devnull, 'w')
  507. self.assertTrue(self.unix._sock_file_in_use(sock_file))
  508. sys.stdout = old_stdout
  509. def test_remove_unused_sock_file_in_use(self):
  510. sock_file = 'temp.sock.file'
  511. self._remove_file(sock_file)
  512. self.assertFalse(self.unix._sock_file_in_use(sock_file))
  513. self._start_unix_sock_server(sock_file)
  514. old_stdout = sys.stdout
  515. sys.stdout = open(os.devnull, 'w')
  516. try:
  517. self.unix._remove_unused_sock_file(sock_file)
  518. except SystemExit:
  519. pass
  520. else:
  521. # This should never happen
  522. self.assertTrue(False)
  523. sys.stdout = old_stdout
  524. def test_remove_unused_sock_file_dir(self):
  525. import tempfile
  526. dir_name = tempfile.mkdtemp()
  527. old_stdout = sys.stdout
  528. sys.stdout = open(os.devnull, 'w')
  529. try:
  530. self.unix._remove_unused_sock_file(dir_name)
  531. except SystemExit:
  532. pass
  533. else:
  534. # This should never happen
  535. self.assertTrue(False)
  536. sys.stdout = old_stdout
  537. os.rmdir(dir_name)
  538. class TestInitialization(unittest.TestCase):
  539. def setEnv(self, name, value):
  540. if value is None:
  541. if name in os.environ:
  542. del os.environ[name]
  543. else:
  544. os.environ[name] = value
  545. def setUp(self):
  546. self._oldSocket = os.getenv("BIND10_XFROUT_SOCKET_FILE")
  547. self._oldFromBuild = os.getenv("B10_FROM_BUILD")
  548. def tearDown(self):
  549. self.setEnv("B10_FROM_BUILD", self._oldFromBuild)
  550. self.setEnv("BIND10_XFROUT_SOCKET_FILE", self._oldSocket)
  551. # Make sure even the computed values are back
  552. xfrout.init_paths()
  553. def testNoEnv(self):
  554. self.setEnv("B10_FROM_BUILD", None)
  555. self.setEnv("BIND10_XFROUT_SOCKET_FILE", None)
  556. xfrout.init_paths()
  557. self.assertEqual(xfrout.UNIX_SOCKET_FILE,
  558. "@@LOCALSTATEDIR@@/auth_xfrout_conn")
  559. def testProvidedSocket(self):
  560. self.setEnv("B10_FROM_BUILD", None)
  561. self.setEnv("BIND10_XFROUT_SOCKET_FILE", "The/Socket/File")
  562. xfrout.init_paths()
  563. self.assertEqual(xfrout.UNIX_SOCKET_FILE, "The/Socket/File")
  564. if __name__== "__main__":
  565. unittest.main()