test_pdns_change_tracker.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. from django.utils import timezone
  2. from desecapi.models import RRset, RR, Domain
  3. from desecapi.pdns_change_tracker import PDNSChangeTracker
  4. from desecapi.tests.base import DesecTestCase
  5. class PdnsChangeTrackerTestCase(DesecTestCase):
  6. empty_domain = None
  7. simple_domain = None
  8. full_domain = None
  9. @classmethod
  10. def setUpTestDataWithPdns(cls):
  11. super().setUpTestDataWithPdns()
  12. cls.empty_domain = Domain.objects.create(
  13. owner=cls.user, name=cls.random_domain_name()
  14. )
  15. cls.simple_domain = Domain.objects.create(
  16. owner=cls.user, name=cls.random_domain_name()
  17. )
  18. cls.full_domain = Domain.objects.create(
  19. owner=cls.user, name=cls.random_domain_name()
  20. )
  21. def assertPdnsZoneUpdate(self, name, rr_sets):
  22. return self.assertPdnsRequests(
  23. [
  24. self.request_pdns_zone_update_assert_body(name, rr_sets),
  25. self.request_pdns_zone_axfr(name),
  26. ],
  27. )
  28. def test_rrset_does_not_exist_exception(self):
  29. tracker = PDNSChangeTracker()
  30. tracker.__enter__()
  31. tracker._rr_set_updated(RRset(domain=self.empty_domain, subname="", type="A"))
  32. with self.assertRaises(ValueError):
  33. tracker.__exit__(None, None, None)
  34. class RRTestCase(PdnsChangeTrackerTestCase):
  35. """
  36. Base-class for checking change tracker behavior for all create, update, and delete operations of the RR model.
  37. """
  38. NUM_OWNED_DOMAINS = 3
  39. SUBNAME = "my_rr_set"
  40. TYPE = "A"
  41. TTL = 334
  42. CONTENT_VALUES = ["2.130.250.238", "170.95.95.252", "128.238.1.5"]
  43. ALT_CONTENT_VALUES = ["190.169.34.46", "216.228.24.25", "151.138.61.173"]
  44. @classmethod
  45. def setUpTestDataWithPdns(cls):
  46. super().setUpTestDataWithPdns()
  47. rr_set_data = dict(subname=cls.SUBNAME, type=cls.TYPE, ttl=cls.TTL)
  48. cls.empty_rr_set = RRset.objects.create(domain=cls.empty_domain, **rr_set_data)
  49. cls.simple_rr_set = RRset.objects.create(
  50. domain=cls.simple_domain, **rr_set_data
  51. )
  52. cls.full_rr_set = RRset.objects.create(domain=cls.full_domain, **rr_set_data)
  53. RR.objects.create(rrset=cls.simple_rr_set, content=cls.CONTENT_VALUES[0])
  54. for content in cls.CONTENT_VALUES:
  55. RR.objects.create(rrset=cls.full_rr_set, content=content)
  56. def assertPdnsEmptyRRSetUpdate(self):
  57. return self.assertPdnsZoneUpdate(self.empty_domain.name, [self.empty_rr_set])
  58. def assertPdnsSimpleRRSetUpdate(self):
  59. return self.assertPdnsZoneUpdate(self.simple_domain.name, [self.simple_rr_set])
  60. def assertPdnsFullRRSetUpdate(self):
  61. return self.assertPdnsZoneUpdate(self.full_domain.name, [self.full_rr_set])
  62. def test_create_in_empty_rr_set(self):
  63. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  64. RR(content=self.CONTENT_VALUES[0], rrset=self.empty_rr_set).save()
  65. def test_create_in_simple_rr_set(self):
  66. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  67. RR(content=self.CONTENT_VALUES[1], rrset=self.simple_rr_set).save()
  68. def test_create_in_full_rr_set(self):
  69. for content in self.ALT_CONTENT_VALUES:
  70. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  71. RR(content=content, rrset=self.full_rr_set).save()
  72. def test_create_multiple_in_empty_rr_set(self):
  73. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  74. for content in self.ALT_CONTENT_VALUES:
  75. RR(content=content, rrset=self.empty_rr_set).save()
  76. def test_create_multiple_in_simple_rr_set(self):
  77. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  78. for content in self.ALT_CONTENT_VALUES:
  79. RR(content=content, rrset=self.simple_rr_set).save()
  80. def test_create_multiple_in_full_rr_set(self):
  81. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  82. for content in self.ALT_CONTENT_VALUES:
  83. RR(content=content, rrset=self.full_rr_set).save()
  84. def test_update_simple_rr_set(self):
  85. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  86. rr = self.simple_rr_set.records.all()[0]
  87. rr.content = self.CONTENT_VALUES[1]
  88. rr.save()
  89. def test_update_full_rr_set_partially(self):
  90. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  91. rr = self.full_rr_set.records.all()[0]
  92. rr.content = self.ALT_CONTENT_VALUES[0]
  93. rr.save()
  94. def test_update_full_rr_set_completely(self):
  95. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  96. for i, rr in enumerate(self.full_rr_set.records.all()):
  97. rr.content = self.ALT_CONTENT_VALUES[i]
  98. rr.save()
  99. def test_delete_simple_rr_set(self):
  100. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  101. self.simple_rr_set.records.all()[0].delete()
  102. def test_delete_full_rr_set_partially(self):
  103. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  104. for rr in self.full_rr_set.records.all()[1:2]:
  105. rr.delete()
  106. def test_delete_full_rr_set_completely(self):
  107. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  108. for rr in self.full_rr_set.records.all():
  109. rr.delete()
  110. def test_create_delete_empty_rr_set(self):
  111. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  112. new_rr = RR.objects.create(
  113. rrset=self.empty_rr_set, content=self.ALT_CONTENT_VALUES[0]
  114. )
  115. RR.objects.create(
  116. rrset=self.empty_rr_set, content=self.ALT_CONTENT_VALUES[1]
  117. )
  118. new_rr.delete()
  119. def test_create_delete_simple_rr_set_1(self):
  120. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  121. new_rr = RR.objects.create(
  122. rrset=self.simple_rr_set, content=self.ALT_CONTENT_VALUES[0]
  123. )
  124. RR.objects.create(
  125. rrset=self.simple_rr_set, content=self.ALT_CONTENT_VALUES[1]
  126. )
  127. new_rr.delete()
  128. def test_create_delete_simple_rr_set_2(self):
  129. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  130. self.simple_rr_set.records.all()[0].delete()
  131. RR.objects.create(
  132. rrset=self.simple_rr_set, content=self.ALT_CONTENT_VALUES[0]
  133. )
  134. def test_create_delete_simple_rr_set_3(self):
  135. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  136. self.simple_rr_set.records.all()[0].delete()
  137. for content in self.ALT_CONTENT_VALUES:
  138. RR.objects.create(rrset=self.simple_rr_set, content=content)
  139. def test_create_delete_full_rr_set_full_replacement(self):
  140. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  141. for rr in self.full_rr_set.records.all():
  142. rr.delete()
  143. for content in self.CONTENT_VALUES:
  144. RR.objects.create(rrset=self.full_rr_set, content=content)
  145. def test_create_delete_full_rr_set_partial_replacement(self):
  146. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  147. self.full_rr_set.records.all()[1].delete()
  148. for content in self.ALT_CONTENT_VALUES[1:]:
  149. RR.objects.create(rrset=self.full_rr_set, content=content)
  150. def test_create_update_empty_rr_set_1(self):
  151. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  152. rr = RR.objects.create(
  153. rrset=self.empty_rr_set, content=self.CONTENT_VALUES[0]
  154. )
  155. rr.content = self.ALT_CONTENT_VALUES[0]
  156. rr.save()
  157. def test_create_update_empty_rr_set_2(self):
  158. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  159. for (content, alt_content) in zip(
  160. self.CONTENT_VALUES, self.ALT_CONTENT_VALUES
  161. ):
  162. rr = RR.objects.create(rrset=self.empty_rr_set, content=content)
  163. rr.content = alt_content
  164. rr.save()
  165. def test_create_update_empty_rr_set_3(self):
  166. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  167. rr = RR.objects.create(
  168. rrset=self.empty_rr_set, content=self.ALT_CONTENT_VALUES[0]
  169. )
  170. RR.objects.create(
  171. rrset=self.empty_rr_set, content=self.ALT_CONTENT_VALUES[1]
  172. )
  173. rr.content = self.CONTENT_VALUES[0]
  174. rr.save()
  175. def test_create_update_simple_rr_set(self):
  176. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  177. rr = self.simple_rr_set.records.all()[0]
  178. RR.objects.create(
  179. rrset=self.simple_rr_set, content=self.ALT_CONTENT_VALUES[0]
  180. )
  181. rr.content = self.ALT_CONTENT_VALUES[1]
  182. rr.save()
  183. def test_create_update_full_rr_set(self):
  184. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  185. for i, rr in enumerate(self.full_rr_set.records.all()):
  186. rr.content = self.ALT_CONTENT_VALUES[i]
  187. rr.save()
  188. RR.objects.create(rrset=self.full_rr_set, content=self.CONTENT_VALUES[0])
  189. def test_update_delete_simple_rr_set(self):
  190. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  191. rr = self.simple_rr_set.records.all()[0]
  192. rr.content = self.ALT_CONTENT_VALUES[0]
  193. rr.save()
  194. rr.delete()
  195. def test_update_delete_full_rr_set(self):
  196. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  197. rr = self.full_rr_set.records.all()[0]
  198. rr.content = self.ALT_CONTENT_VALUES[0]
  199. rr.save()
  200. rr.delete()
  201. self.full_rr_set.records.all()[1].delete()
  202. rr = self.full_rr_set.records.all()[0]
  203. rr.content = self.ALT_CONTENT_VALUES[0]
  204. rr.save()
  205. def test_create_update_delete_empty_rr_set_1(self):
  206. rr = RR.objects.create(rrset=self.empty_rr_set, content=self.CONTENT_VALUES[0])
  207. rr.content = self.ALT_CONTENT_VALUES[0]
  208. rr.save()
  209. rr.delete()
  210. def test_create_update_delete_empty_rr_set_2(self):
  211. with self.assertPdnsEmptyRRSetUpdate(), PDNSChangeTracker():
  212. RR.objects.create(rrset=self.empty_rr_set, content=self.CONTENT_VALUES[0])
  213. rr = RR.objects.create(
  214. rrset=self.empty_rr_set, content=self.CONTENT_VALUES[1]
  215. )
  216. rr.content = self.ALT_CONTENT_VALUES[1]
  217. rr.save()
  218. RR.objects.create(rrset=self.empty_rr_set, content=self.CONTENT_VALUES[2])
  219. rr.delete()
  220. def test_create_update_delete_simple_rr_set(self):
  221. with self.assertPdnsSimpleRRSetUpdate(), PDNSChangeTracker():
  222. self.simple_rr_set.records.all()[0].delete()
  223. RR.objects.create(rrset=self.simple_rr_set, content=self.CONTENT_VALUES[0])
  224. rr = RR.objects.create(
  225. rrset=self.simple_rr_set, content=self.CONTENT_VALUES[1]
  226. )
  227. rr.content = self.ALT_CONTENT_VALUES[1]
  228. rr.save()
  229. def test_create_update_delete_full_rr_set(self):
  230. with self.assertPdnsFullRRSetUpdate(), PDNSChangeTracker():
  231. self.full_rr_set.records.all()[1].delete()
  232. rr = self.full_rr_set.records.all()[1]
  233. rr.content = self.ALT_CONTENT_VALUES[0]
  234. rr.save()
  235. RR.objects.create(
  236. rrset=self.full_rr_set, content=self.ALT_CONTENT_VALUES[1]
  237. )
  238. class AAAARRTestCase(RRTestCase):
  239. SUBNAME = "*.foobar"
  240. TYPE = "AAAA"
  241. TTL = 12
  242. CONTENT_VALUES = [
  243. "2001:fb24:45fd:d51:7937:b375:9cf3:5c62",
  244. "2001:ed06:5ebc:9d:87a:ce9f:1ceb:996",
  245. "2001:aa22:60e8:cec5:5650:9ff9:9a1b:b588",
  246. "2001:3ca:d710:52c2:9748:eec6:2e20:af0b",
  247. "2001:9c6e:8417:3c06:dd1c:44f1:a35f:ffad",
  248. "2001:f67a:5847:8dc0:edc3:56f3:a067:f80e",
  249. "2001:4e21:bda6:a509:e777:91c6:2dc1:394",
  250. "2001:9930:b062:c38f:99f6:ce12:bb04:f7c6",
  251. "2001:bb5e:921:b17f:7c9b:afb6:9933:cc79",
  252. "2001:a861:7139:e21e:11e4:8782:242b:e2a2",
  253. "2001:eaa:ff53:c819:93e:437c:ccc8:330c",
  254. "2001:6a88:fb92:5b43:984b:b729:393b:f173",
  255. ]
  256. ALT_CONTENT_VALUES = [
  257. "2001:2d03:6247:3494:b92e:d4a:2827:e2d",
  258. "2001:4b37:19d6:b66e:1aa1:db0f:98b5:d065",
  259. "2001:dbf1:e401:ace2:bc99:eb22:6e12:ec81",
  260. "2001:fa92:3564:7c3f:9995:2068:58bf:2a45",
  261. "2001:4c2c:c671:9f0c:600e:4eb6:672e:48c7",
  262. "2001:5d09:a6f7:594b:afa4:318a:6eda:3ec6",
  263. "2001:f33a:407c:f4e6:f886:dce2:6d08:d8ae",
  264. "2001:43c8:378d:7d37:92eb:fb0c:26b1:4998",
  265. "2001:7293:88c5:5405:fd1:7334:bb55:be20",
  266. "2001:c4b7:ae76:a9a2:ffb5:ba30:6874:a416",
  267. "2001:175f:7880:ef82:b65a:a472:14c9:a495",
  268. "2001:8c35:1566:4f53:c26a:c54:2c9f:1463",
  269. ]
  270. class TXTRRTestCase(RRTestCase):
  271. SUBNAME = "_acme_challenge"
  272. TYPE = "TXT"
  273. TTL = 876
  274. CONTENT_VALUES = [
  275. '"The quick brown fox jumps over the lazy dog"',
  276. '"main( ) {printf(\\"hello, world\\010\\");}"',
  277. '"“红色联合”对“四·二八兵团”总部大楼的攻击已持续了两天"',
  278. ]
  279. ALT_CONTENT_VALUES = [
  280. '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿 🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 🌂 🧵"',
  281. '"v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.123 a -all"',
  282. '"https://en.wikipedia.org/wiki/Domain_Name_System"',
  283. ]
  284. class RRSetTestCase(PdnsChangeTrackerTestCase):
  285. TEST_DATA = {
  286. ("A", "_asdf", 123): ["1.2.3.4", "5.5.5.5"],
  287. ("TXT", "test", 455): ['"ASDF"', '"foobar"', '"92847"'],
  288. ("A", "foo", 1010): ["1.2.3.4", "5.5.4.5"],
  289. ("AAAA", "*", 100023): ["::1", "::2", "::3", "::4"],
  290. }
  291. ADDITIONAL_TEST_DATA = {
  292. ("A", "zekdi", 99): [
  293. "134.48.204.28",
  294. "151.85.162.150",
  295. "5.174.133.123",
  296. "96.37.218.195",
  297. "106.18.66.163",
  298. "51.75.149.213",
  299. "9.105.0.185",
  300. "32.198.60.88",
  301. "93.141.131.151",
  302. "6.133.10.124",
  303. ],
  304. ("A", "knebq", 82): ["218.154.60.184"],
  305. }
  306. @classmethod
  307. def _create_rr_sets(cls, data, domain):
  308. rr_sets = []
  309. rrs = {}
  310. for (type_, subname, ttl), rr_contents in data.items():
  311. rr_set = RRset(domain=domain, subname=subname, type=type_, ttl=ttl)
  312. rr_sets.append(rr_set)
  313. rrs[(type_, subname)] = this_rrs = []
  314. rr_set.save()
  315. for content in rr_contents:
  316. rr = RR(content=content, rrset=rr_set)
  317. this_rrs.append(rr)
  318. rr.save()
  319. return rr_sets, rrs
  320. @classmethod
  321. def setUpTestDataWithPdns(cls):
  322. super().setUpTestDataWithPdns()
  323. cls.rr_sets, cls.rrs = cls._create_rr_sets(cls.TEST_DATA, cls.full_domain)
  324. def test_empty_domain_create_single_empty(self):
  325. with PDNSChangeTracker():
  326. RRset.objects.create(domain=self.empty_domain, subname="", ttl=60, type="A")
  327. def test_empty_domain_create_single_meaty(self):
  328. with self.assertPdnsZoneUpdate(
  329. self.empty_domain.name, self.empty_domain.rrset_set
  330. ), PDNSChangeTracker():
  331. self._create_rr_sets(self.ADDITIONAL_TEST_DATA, self.empty_domain)
  332. def test_full_domain_create_single_empty(self):
  333. with PDNSChangeTracker():
  334. RRset.objects.create(domain=self.full_domain, subname="", ttl=60, type="A")
  335. def test_empty_domain_create_many_empty(self):
  336. with PDNSChangeTracker():
  337. empty_test_data = {key: [] for key, value in self.TEST_DATA.items()}
  338. self._create_rr_sets(empty_test_data, self.empty_domain)
  339. def test_empty_domain_create_many_meaty(self):
  340. with self.assertPdnsZoneUpdate(
  341. self.empty_domain.name, self.empty_domain.rrset_set
  342. ), PDNSChangeTracker():
  343. self._create_rr_sets(self.TEST_DATA, self.empty_domain)
  344. def test_empty_domain_delete(self):
  345. with PDNSChangeTracker():
  346. self._create_rr_sets(self.TEST_DATA, self.empty_domain)
  347. for rr_set in self.empty_domain.rrset_set.all():
  348. rr_set.delete()
  349. def test_full_domain_delete_single(self):
  350. index = (self.rr_sets[0].type, self.rr_sets[0].subname, self.rr_sets[0].ttl)
  351. with self.assertPdnsZoneUpdate(
  352. self.full_domain.name, [self.TEST_DATA[index]]
  353. ), PDNSChangeTracker():
  354. self.rr_sets[0].delete()
  355. def test_full_domain_delete_multiple(self):
  356. data = self.TEST_DATA
  357. empty_data = {key: [] for key, value in data.items()}
  358. with self.assertPdnsZoneUpdate(
  359. self.full_domain.name, empty_data
  360. ), PDNSChangeTracker():
  361. for type_, subname, _ in data.keys():
  362. self.full_domain.rrset_set.get(subname=subname, type=type_).delete()
  363. def test_update_ttl(self):
  364. new_ttl = 765
  365. data = {
  366. (type_, subname, new_ttl): records
  367. for (type_, subname, _), records in self.TEST_DATA.items()
  368. }
  369. with self.assertPdnsZoneUpdate(
  370. self.full_domain.name, data
  371. ), PDNSChangeTracker():
  372. for rr_set in self.full_domain.rrset_set.all():
  373. rr_set.ttl = new_ttl
  374. rr_set.save()
  375. def test_full_domain_create_delete(self):
  376. data = self.TEST_DATA
  377. empty_data = {key: [] for key, value in data.items()}
  378. with self.assertPdnsZoneUpdate(
  379. self.full_domain.name, empty_data
  380. ), PDNSChangeTracker():
  381. self._create_rr_sets(self.ADDITIONAL_TEST_DATA, self.full_domain)
  382. for type_, subname, _ in data.keys():
  383. self.full_domain.rrset_set.get(subname=subname, type=type_).delete()
  384. class CommonRRSetTestCase(RRSetTestCase):
  385. def test_mixed_operations(self):
  386. with self.assertPdnsZoneUpdate(
  387. self.full_domain.name, self.ADDITIONAL_TEST_DATA
  388. ), PDNSChangeTracker():
  389. self._create_rr_sets(self.ADDITIONAL_TEST_DATA, self.full_domain)
  390. rr_sets = [
  391. RRset.objects.get(type=type_, subname=subname)
  392. for (type_, subname, _) in self.ADDITIONAL_TEST_DATA.keys()
  393. ]
  394. with self.assertPdnsZoneUpdate(
  395. self.full_domain.name, rr_sets
  396. ), PDNSChangeTracker():
  397. for rr_set in rr_sets:
  398. rr_set.ttl = 1
  399. rr_set.save()
  400. data = {}
  401. for key in [("A", "_asdf", 123), ("AAAA", "*", 100023), ("A", "foo", 1010)]:
  402. data[key] = self.TEST_DATA[key].copy()
  403. with self.assertPdnsZoneUpdate(
  404. self.full_domain.name, data
  405. ), PDNSChangeTracker():
  406. data[("A", "_asdf", 123)].append("9.9.9.9")
  407. rr_set = RRset.objects.get(
  408. domain=self.full_domain, type="A", subname="_asdf"
  409. )
  410. RR(content="9.9.9.9", rrset=rr_set).save()
  411. data[("AAAA", "*", 100023)].append("::9")
  412. rr_set = RRset.objects.get(
  413. domain=self.full_domain, type="AAAA", subname="*"
  414. )
  415. RR(content="::9", rrset=rr_set).save()
  416. data[("A", "foo", 1010)] = []
  417. RRset.objects.get(domain=self.full_domain, type="A", subname="foo").delete()
  418. class UncommonRRSetTestCase(RRSetTestCase):
  419. TEST_DATA = {
  420. ("SPF", "baz", 444): [
  421. '"v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.123 a -all"',
  422. '"v=spf1 a mx ip4:192.0.2.0 -all"',
  423. ],
  424. (
  425. "OPENPGPKEY",
  426. "00d8d3f11739d2f3537099982b4674c29fc59a8fda350fca1379613a._openpgpkey",
  427. 78000,
  428. ): [
  429. "mQENBFnVAMgBCADWXo3I9Vig02zCR8WzGVN4FUrexZh9OdVSjOeSSmXPH6V5"
  430. "+sWRfgSvtUp77IWQtZU810EI4GgcEzg30SEdLBSYZAt/lRWSpcQWnql4LvPg"
  431. "oMqU+/+WUxFdnbIDGCMEwWzF2NtQwl4r/ot/q5SHoaA4AGtDarjA1pbTBxza"
  432. "/xh6VRQLl5vhWRXKslh/Tm4NEBD16Z9gZ1CQ7YlAU5Mg5Io4ghOnxWZCGJHV"
  433. "5BVQTrzzozyILny3e48dIwXJKgcFt/DhE+L9JTrO4cYtkG49k7a5biMiYhKh"
  434. "LK3nvi5diyPyHYQfUaD5jO5Rfcgwk7L4LFinVmNllqL1mgoxadpgPE8xABEB"
  435. "AAG0MUpvaGFubmVzIFdlYmVyIChPTkxZLVRFU1QpIDxqb2hhbm5lc0B3ZWJl"
  436. "cmRucy5kZT6JATgEEwECACIFAlnVAMgCGwMGCwkIBwMCBhUIAgkKCwQWAgMB"
  437. "Ah4BAheAAAoJEOvytPeP0jpogccH/1IQNza/JPiQRFLWwzz1mxOSgRgubkOw"
  438. "+XgXAtvIGHQOF6/ZadQ8rNrMb3D+dS4bTkwpFemY59Bm3n12Ve2Wv2AdN8nK"
  439. "1KLClA9cP8380CT53+zygV+mGfoRBLRO0i4QmW3mI6yg7T2E+U20j/i9IT1K"
  440. "ATg4oIIgLn2bSpxRtuSp6aJ2q91Y/lne7Af7KbKq/MirEDeSPrjMYxK9D74E"
  441. "ABLs4Ab4Rebg3sUga037yTOCYDpRv2xkyARoXMWYlRqME/in7aBtfo/fduJG"
  442. "qu2RlND4inQmV75V+s4/x9u+7UlyFIMbWX2rtdWHsO/t4sCP1hhTZxz7kvK7"
  443. "1ZqLj9hVjdW5AQ0EWdUAyAEIAKxTR0AcpiDm4r4Zt/qGD9P9jasNR0qkoHjr"
  444. "9tmkaW34Lx7wNTDbSYQwn+WFzoT1rxbpge+IpjMn5KabHc0vh13vO1zdxvc0"
  445. "LSydhjMI1Gfey+rsQxhT4p5TbvKpsWiNykSNryl1LRgRvcWMnxvYfxdyqIF2"
  446. "3+3pgMipXlfJHX4SoAuPn4Bra84y0ziljrptWf4U78+QonX9dwwZ/SCrSPfQ"
  447. "rGwpQcHSbbxZvxmgxeweHuAEhUGVuwkFsNBSk4NSi+7Y1p0/oD7tEM17WjnO"
  448. "NuoGCFh1anTS7+LE0f3Mp0A74GeJvnkgdnPHJwcZpBf5Jf1/6Nw/tJpYiP9v"
  449. "Fu1nF9EAEQEAAYkBHwQYAQIACQUCWdUAyAIbDAAKCRDr8rT3j9I6aDZrB/9j"
  450. "2sgCohhDBr/Yzxlg3OmRwnvJlHjs//57XV99ssWAg142HxMQt87s/AXpIuKH"
  451. "tupEAClN/knrmKubO3JUkoi3zCDkFkSgrH2Mos75KQbspUtmzwVeGiYSNqyG"
  452. "pEzh5UWYuigYx1/a5pf3EhXCVVybIJwxDEo6sKZwYe6CRe5fQpY6eqZNKjkl"
  453. "4xDogTMpsrty3snjZHOsQYlTlFWFsm1KA43Mnaj7Pfn35+8bBeNSgiS8R+EL"
  454. "f66Ymcl9YHWHHTXjs+DvsrimYbs1GXOyuu3tHfKlZH19ZevXbycpp4UFWsOk"
  455. "Sxsb3CZRnPxuz+NjZrOk3UNI6RxlaeuAQOBEow50"
  456. ],
  457. ("PTR", "foo", 1010): ["1.example.com.", "2.example.com."],
  458. ("SRV", "*", 100023): [
  459. "10 60 5060 1.example.com.",
  460. "20 60 5060 2.example.com.",
  461. "30 60 5060 3.example.com.",
  462. ],
  463. ("TLSA", "_443._tcp.www", 89): [
  464. "3 0 1 221C1A9866C32A45E44F55F611303242082A01C1B5C3027C8C7AD1324DE0AC38"
  465. ],
  466. }
  467. class DomainTestCase(PdnsChangeTrackerTestCase):
  468. def __init__(self, *args, **kwargs):
  469. super().__init__(*args, **kwargs)
  470. self.full_domain = None
  471. self.simple_domain = None
  472. self.empty_domain = None
  473. self.domains = []
  474. def setUp(self):
  475. super().setUp()
  476. self.empty_domain = Domain.objects.create(
  477. name=self.random_domain_name(), owner=self.user
  478. )
  479. self.simple_domain = Domain.objects.create(
  480. name=self.random_domain_name(), owner=self.user
  481. )
  482. self.full_domain = Domain.objects.create(
  483. name=self.random_domain_name(), owner=self.user
  484. )
  485. self.domains = [self.empty_domain, self.simple_domain, self.full_domain]
  486. simple_rr_set = RRset.objects.create(
  487. domain=self.simple_domain, type="AAAA", subname="", ttl=42
  488. )
  489. RR.objects.create(content="::1", rrset=simple_rr_set)
  490. RR.objects.create(content="::2", rrset=simple_rr_set)
  491. rr_set_1 = RRset.objects.create(
  492. domain=self.full_domain, type="A", subname="*", ttl=1337
  493. )
  494. for content in [self.random_ip(4) for _ in range(10)]:
  495. RR.objects.create(content=content, rrset=rr_set_1)
  496. rr_set_2 = RRset.objects.create(
  497. domain=self.full_domain, type="AAAA", subname="", ttl=60
  498. )
  499. for content in [self.random_ip(6) for _ in range(15)]:
  500. RR.objects.create(content=content, rrset=rr_set_2)
  501. def test_create(self):
  502. name = self.random_domain_name()
  503. with self.assertPdnsRequests(
  504. [
  505. self.request_pdns_zone_create("LORD"),
  506. self.request_pdns_zone_create("MASTER"),
  507. self.request_pdns_update_catalog(),
  508. self.request_pdns_zone_axfr(name),
  509. ]
  510. ), PDNSChangeTracker():
  511. Domain.objects.create(name=name, owner=self.user)
  512. def test_update_domain(self):
  513. for domain in self.domains:
  514. with PDNSChangeTracker():
  515. domain.owner = self.admin
  516. domain.published = timezone.now()
  517. domain.save()
  518. def test_update_empty_domain_name(self):
  519. new_name = self.random_domain_name()
  520. with PDNSChangeTracker(): # no exception, no requests
  521. self.empty_domain.name = new_name
  522. self.empty_domain.save()
  523. def test_delete_single(self):
  524. for domain in self.domains:
  525. with self.assertPdnsRequests(
  526. self.requests_desec_domain_deletion(domain)
  527. ), PDNSChangeTracker():
  528. domain.delete()
  529. def test_delete_multiple(self):
  530. with self.assertPdnsRequests(
  531. [
  532. self.requests_desec_domain_deletion(domain)
  533. for domain in reversed(self.domains)
  534. ],
  535. expect_order=False,
  536. ), PDNSChangeTracker():
  537. for domain in self.domains:
  538. domain.delete()
  539. def test_create_delete(self):
  540. with PDNSChangeTracker():
  541. d = Domain.objects.create(name=self.random_domain_name(), owner=self.user)
  542. d.delete()
  543. def test_delete_create_empty_domain(self):
  544. with PDNSChangeTracker():
  545. name = self.empty_domain.name
  546. self.empty_domain.delete()
  547. self.empty_domain = Domain.objects.create(name=name, owner=self.user)
  548. def test_delete_create_full_domain(self):
  549. name = self.full_domain.name
  550. with self.assertPdnsZoneUpdate(name, []), PDNSChangeTracker():
  551. self.full_domain.delete()
  552. self.full_domain = Domain.objects.create(name=name, owner=self.user)