test_dyndns12update.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import random
  2. from rest_framework import status
  3. from desecapi.tests.base import DynDomainOwnerTestCase
  4. class DynDNS12UpdateTest(DynDomainOwnerTestCase):
  5. def assertIP(self, ipv4=None, ipv6=None, name=None):
  6. name = name or self.my_domain.name.lower()
  7. for type_, value in [('A', ipv4), ('AAAA', ipv6)]:
  8. response = self.client_token_authorized.get(self.reverse('v1:rrset', name=name, subname='', type=type_))
  9. if value:
  10. self.assertStatus(response, status.HTTP_200_OK)
  11. self.assertEqual(response.data['records'][0], value)
  12. self.assertEqual(response.data['ttl'], 60)
  13. else:
  14. self.assertStatus(response, status.HTTP_404_NOT_FOUND)
  15. def test_identification_by_domain_name(self):
  16. self.client.set_credentials_basic_auth(self.my_domain.name + '.invalid', self.token.key)
  17. response = self.assertDynDNS12NoUpdate(mock_remote_addr='10.5.5.6')
  18. self.assertStatus(response, status.HTTP_401_UNAUTHORIZED)
  19. def test_identification_by_query_params(self):
  20. # /update?username=foobar.dedyn.io&password=secret
  21. self.client.set_credentials_basic_auth(None, None)
  22. response = self.assertDynDNS12Update(username=self.my_domain.name, password=self.token.key)
  23. self.assertStatus(response, status.HTTP_200_OK)
  24. self.assertEqual(response.data, 'good')
  25. self.assertIP(ipv4='127.0.0.1')
  26. def test_deviant_ttl(self):
  27. """
  28. The dynamic update will try to set the TTL to 60. Here, we create
  29. a record with a different TTL beforehand and then make sure that
  30. updates still work properly.
  31. """
  32. with self.assertPdnsRequests(
  33. self.request_pdns_zone_update(self.my_domain.name),
  34. self.request_pdns_zone_axfr(self.my_domain.name),
  35. ):
  36. response = self.client_token_authorized.patch_rr_set(
  37. self.my_domain.name.lower(), subname='', type_='A', ttl=3600)
  38. self.assertStatus(response, status.HTTP_200_OK)
  39. response = self.assertDynDNS12Update(self.my_domain.name)
  40. self.assertStatus(response, status.HTTP_200_OK)
  41. self.assertEqual(response.data, 'good')
  42. self.assertIP(ipv4='127.0.0.1')
  43. def test_ddclient_dyndns1_v4_success(self):
  44. # /nic/dyndns?action=edit&started=1&hostname=YES&host_id=foobar.dedyn.io&myip=10.1.2.3
  45. with self.assertPdnsRequests(
  46. self.request_pdns_zone_update(self.my_domain.name),
  47. self.request_pdns_zone_axfr(self.my_domain.name),
  48. ):
  49. response = self.client.get(
  50. self.reverse('v1:dyndns12update'),
  51. {
  52. 'action': 'edit',
  53. 'started': 1,
  54. 'hostname': 'YES',
  55. 'host_id': self.my_domain.name,
  56. 'myip': '10.1.2.3'
  57. }
  58. )
  59. self.assertStatus(response, status.HTTP_200_OK)
  60. self.assertEqual(response.data, 'good')
  61. self.assertIP(ipv4='10.1.2.3')
  62. # Repeat and make sure that no pdns request is made (not even for the empty AAAA record)
  63. response = self.client.get(
  64. self.reverse('v1:dyndns12update'),
  65. {
  66. 'action': 'edit',
  67. 'started': 1,
  68. 'hostname': 'YES',
  69. 'host_id': self.my_domain.name,
  70. 'myip': '10.1.2.3'
  71. }
  72. )
  73. self.assertStatus(response, status.HTTP_200_OK)
  74. def test_ddclient_dyndns1_v6_success(self):
  75. # /nic/dyndns?action=edit&started=1&hostname=YES&host_id=foobar.dedyn.io&myipv6=::1337
  76. response = self.assertDynDNS12Update(
  77. domain_name=self.my_domain.name,
  78. action='edit',
  79. started=1,
  80. hostname='YES',
  81. host_id=self.my_domain.name,
  82. myipv6='::1337'
  83. )
  84. self.assertStatus(response, status.HTTP_200_OK)
  85. self.assertEqual(response.data, 'good')
  86. self.assertIP(ipv4='127.0.0.1', ipv6='::1337')
  87. # Repeat and make sure that no pdns request is made (not even for the empty A record)
  88. response = self.client.get(
  89. self.reverse('v1:dyndns12update'),
  90. {
  91. 'domain_name': self.my_domain.name,
  92. 'action': 'edit',
  93. 'started': 1,
  94. 'hostname': 'YES',
  95. 'host_id': self.my_domain.name,
  96. 'myipv6': '::1337'
  97. }
  98. )
  99. self.assertStatus(response, status.HTTP_200_OK)
  100. def test_ddclient_dyndns2_v4_success(self):
  101. # /nic/update?system=dyndns&hostname=foobar.dedyn.io&myip=10.2.3.4
  102. response = self.assertDynDNS12Update(
  103. domain_name=self.my_domain.name,
  104. system='dyndns',
  105. hostname=self.my_domain.name,
  106. myip='10.2.3.4',
  107. )
  108. self.assertStatus(response, status.HTTP_200_OK)
  109. self.assertEqual(response.data, 'good')
  110. self.assertIP(ipv4='10.2.3.4')
  111. def test_ddclient_dyndns2_v6_success(self):
  112. # /nic/update?system=dyndns&hostname=foobar.dedyn.io&myipv6=::1338
  113. response = self.assertDynDNS12Update(
  114. domain_name=self.my_domain.name,
  115. system='dyndns',
  116. hostname=self.my_domain.name,
  117. myipv6='::666',
  118. )
  119. self.assertStatus(response, status.HTTP_200_OK)
  120. self.assertEqual(response.data, 'good')
  121. self.assertIP(ipv4='127.0.0.1', ipv6='::666')
  122. def test_fritz_box(self):
  123. # /
  124. response = self.assertDynDNS12Update(self.my_domain.name)
  125. self.assertStatus(response, status.HTTP_200_OK)
  126. self.assertEqual(response.data, 'good')
  127. self.assertIP(ipv4='127.0.0.1')
  128. def test_unset_ip(self):
  129. for (v4, v6) in [
  130. ('127.0.0.1', '::1'),
  131. ('127.0.0.1', ''),
  132. ('', '::1'),
  133. ('', ''),
  134. ]:
  135. response = self.assertDynDNS12Update(self.my_domain.name, ip=v4, ipv6=v6)
  136. self.assertStatus(response, status.HTTP_200_OK)
  137. self.assertEqual(response.data, 'good')
  138. self.assertIP(ipv4=v4, ipv6=v6)
  139. class SingleDomainDynDNS12UpdateTest(DynDNS12UpdateTest):
  140. NUM_OWNED_DOMAINS = 1
  141. def test_identification_by_token(self):
  142. self.client.set_credentials_basic_auth('', self.token.key)
  143. response = self.assertDynDNS12Update(self.my_domain.name, mock_remote_addr='10.5.5.6')
  144. self.assertStatus(response, status.HTTP_200_OK)
  145. self.assertEqual(response.data, 'good')
  146. self.assertIP(ipv4='10.5.5.6')
  147. def test_identification_by_email(self):
  148. self.client.set_credentials_basic_auth(self.owner.email, self.token.key)
  149. response = self.assertDynDNS12Update(self.my_domain.name, mock_remote_addr='10.5.5.6')
  150. self.assertStatus(response, status.HTTP_200_OK)
  151. self.assertEqual(response.data, 'good')
  152. self.assertIP(ipv4='10.5.5.6')
  153. class MultipleDomainDynDNS12UpdateTest(DynDNS12UpdateTest):
  154. NUM_OWNED_DOMAINS = 4
  155. def test_identification_by_token(self):
  156. """
  157. Test if the conflict of having multiple domains, but not specifying which to update is correctly recognized.
  158. """
  159. self.client.set_credentials_basic_auth('', self.token.key)
  160. response = self.client.get(self.reverse('v1:dyndns12update'), REMOTE_ADDR='10.5.5.7')
  161. self.assertStatus(response, status.HTTP_409_CONFLICT)
  162. class MixedCaseDynDNS12UpdateTestCase(DynDNS12UpdateTest):
  163. @staticmethod
  164. def random_casing(s):
  165. return ''.join([c.lower() if random.choice([True, False]) else c.upper() for c in s])
  166. def setUp(self):
  167. super().setUp()
  168. self.my_domain.name = self.random_casing(self.my_domain.name)
  169. class UppercaseDynDNS12UpdateTestCase(DynDNS12UpdateTest):
  170. def setUp(self):
  171. super().setUp()
  172. self.my_domain.name = self.my_domain.name.upper()