No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

forms.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. # This file is part of dnmgmt, a number resource management system
  2. # Licensed under GNU General Public License v3 or later
  3. # Written by Sebastian Lohff (seba@someserver.de)
  4. from django import forms
  5. from django.db.models import Q
  6. from whoisdb.models import InetNum
  7. from whoisdb.forms import MntFormMixin, WhoisObjectFormMixin
  8. from whoisdb.validators import IP46CIDRValidator
  9. from .models import Domain, Nameserver, ReverseZone
  10. import re
  11. import ipaddress
  12. class DomainForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
  13. class Meta:
  14. model = Domain
  15. fields = ['name', 'nameservers', 'mnt_by', 'admin_c']
  16. def __init__(self, *args, **kwargs):
  17. super(DomainForm, self).__init__(*args, **kwargs)
  18. mnts = self._user.maintainer_set.all()
  19. self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
  20. instance = getattr(self, "instance", None)
  21. self._create = not (instance and instance.pk)
  22. if not self._create:
  23. self.fields['name'].disabled = True
  24. self.fields['nameservers'].queryset |= self.instance.nameservers.all()
  25. self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct()
  26. def clean_name(self):
  27. name = self.cleaned_data['name'].lower()
  28. if self._create:
  29. if not name.endswith("."):
  30. name += "."
  31. if not name.endswith("dn."):
  32. raise forms.ValidationError("Only .dn domains can be registered at this point")
  33. if name.count(".") > 2:
  34. raise forms.ValidationError("No subdomains can be registered")
  35. if not re.match("^[a-z0-9.-]+$", name):
  36. raise forms.ValidationError("Only a-z, 0-9 and - are allowed inside the domain name")
  37. try:
  38. Domain.objects.get(name=name)
  39. raise forms.ValidationError("Domain already exists")
  40. except Domain.DoesNotExist:
  41. pass
  42. return name
  43. class NameserverForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
  44. class Meta:
  45. model = Nameserver
  46. fields = ['name', 'glueIPv4', 'glueIPv6', 'mnt_by', 'admin_c']
  47. help_texts = {
  48. "glueIPv4": "Note: You can only set a glue record if the base domain of this nameserver belongs to you!"
  49. }
  50. def __init__(self, *args, **kwargs):
  51. super(NameserverForm, self).__init__(*args, **kwargs)
  52. instance = getattr(self, "instance", None)
  53. self._create = not (instance and instance.pk)
  54. def cleanNetwork(self, glue):
  55. ip = ipaddress.ip_address(glue)
  56. proto = InetNum.IPv4 if ip.version == 4 else InetNum.IPv6
  57. nets = InetNum.objects.filter(parent_range=None, protocol=proto)
  58. if len(nets) == 0:
  59. raise forms.ValidationError("No range has been registered for IPv%s in the whois interface" % ip.version)
  60. for net in nets:
  61. if ip in net.getNetwork():
  62. break
  63. else:
  64. raise forms.ValidationError("Glue record address is not inside DarkNet (subnet %s)" % ", ".join(map(lambda _x: _x.prefix(), nets)))
  65. def clean_glueIPv4(self):
  66. glue = self.cleaned_data['glueIPv4']
  67. if glue:
  68. self.cleanNetwork(glue)
  69. return glue
  70. def clean_glueIPv6(self):
  71. glue = self.cleaned_data['glueIPv6']
  72. if glue:
  73. self.cleanNetwork(glue)
  74. return glue
  75. def clean_name(self):
  76. name = self.cleaned_data['name'].lower().strip()
  77. if not name.endswith("."):
  78. name += "."
  79. # allow name to stay if it did not change
  80. if not self._create and self.instance.name == name:
  81. return name
  82. if name.count(".") <= 2:
  83. raise forms.ValidationError("Nameserver must be inside a domain (e.g. ns1.noot.dn.)")
  84. mnts = self._user.maintainer_set.all()
  85. try:
  86. obj = Nameserver.objects.get(name=name, mnt_by__in=mnts)
  87. if self._create or not self._create and obj.pk != self.instance.pk:
  88. raise forms.ValidationError("You already have a nameserver with this name under your control")
  89. except Nameserver.DoesNotExist:
  90. pass
  91. except Nameserver.MultipleObjectsReturned:
  92. pass
  93. return name
  94. def clean(self):
  95. cleaned_data = super(NameserverForm, self).clean()
  96. if not self.errors:
  97. name = cleaned_data.get("name")
  98. mntBy = cleaned_data.get("mnt_by")
  99. zone = ".".join(name.split(".")[-3:])
  100. ipv4 = cleaned_data.get("glueIPv4", None)
  101. ipv6 = cleaned_data.get("glueIPv6", None)
  102. if not ipv4:
  103. ipv4 = None
  104. if not ipv6:
  105. ipv6 = None
  106. if self._create and (ipv4 or ipv6) or not self._create and not (self.instance.glueIPv4 == ipv4 and self.instance.glueIPv6 == ipv6):
  107. mnts = self._user.maintainer_set.all()
  108. domains = Domain.objects.filter(mnt_by__in=mnts)
  109. found = False
  110. for domain in domains:
  111. if domain.name == zone:
  112. found = True
  113. break
  114. if not found:
  115. raise forms.ValidationError("You have glue IPs set, but this domain is not under a domain you control.")
  116. if ipv4 or ipv6:
  117. try:
  118. ns = Nameserver.objects.get(Q(name=name) & (Q(glueIPv4__isnull=False) | Q(glueIPv6__isnull=False)))
  119. if self._create or ns.pk != self.instance.pk:
  120. nsMnts = ", ".join(n.handle for n in ns.mnt_by.all())
  121. raise forms.ValidationError("Only one nameserver for this domain can have glue records and one already exists (maintained by %s)" % nsMnts)
  122. except Nameserver.DoesNotExist:
  123. pass
  124. failedMnts = set()
  125. for ns in Nameserver.objects.filter(name=name, mnt_by__in=mntBy):
  126. if self._create or self.instance.pk != ns.pk:
  127. for mnt in ns.mnt_by.all():
  128. if mnt in mntBy:
  129. failedMnts.add(mnt.handle)
  130. if len(failedMnts) > 0:
  131. raise forms.ValidationError("The following maintainer objects already have this nameservers: %s" % ", ".join(failedMnts))
  132. return cleaned_data
  133. class ReverseZoneForm(forms.ModelForm):
  134. prefix = forms.CharField(validators=[IP46CIDRValidator])
  135. class Meta:
  136. model = ReverseZone
  137. fields = ['parentNet', 'nameservers']
  138. help_texts = {
  139. "prefix": "The prefix in CIDR form for which this object is responsible",
  140. }
  141. def __init__(self, user, *args, **kwargs):
  142. self._user = user
  143. super(ReverseZoneForm, self).__init__(*args, **kwargs)
  144. instance = getattr(self, "instance", None)
  145. self._create = not (instance and instance.pk)
  146. mnts = self._user.maintainer_set.all()
  147. self.fields['parentNet'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
  148. self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
  149. if not self._create:
  150. self.fields['prefix'].disabled = True
  151. self.fields['nameservers'].queryset |= self.instance.nameservers.all()
  152. self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct()
  153. def clean_prefix(self):
  154. prefix = self.cleaned_data['prefix']
  155. net = ipaddress.ip_network(prefix)
  156. if net.version == 6 and net.prefixlen % 4 != 0:
  157. raise forms.ValidationError("IPv6 reverse zone prefix length has to be a multiple of 4")
  158. return prefix
  159. def clean(self):
  160. cleaned_data = super(ReverseZoneForm, self).clean()
  161. if not self.errors:
  162. if self._create:
  163. net = ipaddress.ip_network(cleaned_data['prefix'])
  164. parentNet = cleaned_data['parentNet'].getNetwork()
  165. if net.network_address not in parentNet:
  166. raise forms.ValidationError("Given prefix %s is not inside of parent netblock %s" % (net, parentNet))
  167. # For now just check all the zones...
  168. #zones = ReverseZone.objects.filter(parentNet=cleaned_data['parentNet'])
  169. zones = ReverseZone.objects.all()
  170. for zone in zones:
  171. if net.network_address in zone.parentNet.getNetwork():
  172. raise forms.ValidationError("Given prefix already has a reverse zone object associated to it: %s" % zone)
  173. self.instance.address = str(net.network_address)
  174. self.instance.netmask = net.prefixlen
  175. return cleaned_data