diff --git a/api/serializers.py b/api/serializers.py index d4e50702..a4fa57bc 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -829,6 +829,25 @@ class DNSZonesSerializer(serializers.ModelSerializer): 'aaaa_records', 'cname_records', 'sshfp_records') +class DNSReverseZonesSerializer(serializers.ModelSerializer): + """Serialize the data about DNS Zones. + """ + soa = SOARecordSerializer(source='extension.soa') + extension = serializers.CharField(source='extension.name', read_only=True) + cidrs = serializers.ListField(child=serializers.CharField(), source='ip_set_cidrs_as_str', read_only=True) + ns_records = NSRecordSerializer(many=True, source='extension.ns_set') + mx_records = MXRecordSerializer(many=True, source='extension.mx_set') + txt_records = TXTRecordSerializer(many=True, source='extension.txt_set') + ptr_records = ARecordSerializer(many=True, source='get_associated_ptr_records') + ptr_v6_records = AAAARecordSerializer(many=True, source='get_associated_ptr_v6_records') + + + class Meta: + model = machines.IpType + fields = ('type', 'extension', 'soa', 'ns_records', 'mx_records', + 'txt_records', 'ptr_records', 'ptr_v6_records', 'cidrs', + 'prefix_v6') + # MAILING diff --git a/api/urls.py b/api/urls.py index 15a19d59..3bcaee0e 100644 --- a/api/urls.py +++ b/api/urls.py @@ -105,6 +105,7 @@ router.register_view(r'localemail/users', views.LocalEmailUsersView), router.register_view(r'firewall/subnet-ports', views.SubnetPortsOpenView), # DNS router.register_view(r'dns/zones', views.DNSZonesView), +router.register_view(r'dns/reverse-zones', views.DNSReverseZonesView), # MAILING router.register_view(r'mailing/standard', views.StandardMailingView), router.register_view(r'mailing/club', views.ClubMailingView), diff --git a/api/views.py b/api/views.py index f84903e6..f284abbe 100644 --- a/api/views.py +++ b/api/views.py @@ -561,6 +561,15 @@ class DNSZonesView(generics.ListAPIView): .all()) serializer_class = serializers.DNSZonesSerializer +class DNSReverseZonesView(generics.ListAPIView): + """Exposes the detailed information about each extension (hostnames, + IPs, DNS records, etc.) in order to build the DNS zone files. + """ + queryset = (machines.IpType.objects.all()) + serializer_class = serializers.DNSReverseZonesSerializer + + + # MAILING diff --git a/machines/forms.py b/machines/forms.py index ecffcc71..49150349 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -218,7 +218,9 @@ class IpTypeForm(FormRevMixin, ModelForm): class Meta: model = IpType fields = ['type', 'extension', 'need_infra', 'domaine_ip_start', - 'domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports'] + 'domaine_ip_stop', 'dnssec_reverse_v4', 'prefix_v6', + 'prefix_v6_length','dnssec_reverse_v6', 'vlan', + 'ouverture_ports'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -230,7 +232,8 @@ class EditIpTypeForm(IpTypeForm): """Edition d'un iptype. Pas d'edition du rangev4 possible, car il faudrait synchroniser les objets iplist""" class Meta(IpTypeForm.Meta): - fields = ['extension', 'type', 'need_infra', 'prefix_v6', 'vlan', + fields = ['extension', 'type', 'need_infra', 'prefix_v6', 'prefix_v6_length', + 'vlan', 'dnssec_reverse_v4', 'dnssec_reverse_v6', 'ouverture_ports'] diff --git a/machines/migrations/0087_dnssec.py b/machines/migrations/0087_dnssec.py new file mode 100644 index 00000000..cc2a25ec --- /dev/null +++ b/machines/migrations/0087_dnssec.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-06-25 15:06 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0086_role'), + ] + + operations = [ + migrations.AddField( + model_name='iptype', + name='dnssec_reverse_v4', + field=models.BooleanField(default=False, help_text='Activer DNSSEC sur le reverse DNS IPv4'), + ), + migrations.AddField( + model_name='iptype', + name='dnssec_reverse_v6', + field=models.BooleanField(default=False, help_text='Activer DNSSEC sur le reverse DNS IPv6'), + ), + ] diff --git a/machines/migrations/0088_iptype_prefix_v6_length.py b/machines/migrations/0088_iptype_prefix_v6_length.py new file mode 100644 index 00000000..e061167c --- /dev/null +++ b/machines/migrations/0088_iptype_prefix_v6_length.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-07-16 18:46 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0087_dnssec'), + ] + + operations = [ + migrations.AddField( + model_name='iptype', + name='prefix_v6_length', + field=models.IntegerField(default=64, validators=[django.core.validators.MaxValueValidator(128), django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/machines/models.py b/machines/models.py index e981bf10..2f5a6a62 100644 --- a/machines/models.py +++ b/machines/models.py @@ -41,8 +41,8 @@ from django.dispatch import receiver from django.forms import ValidationError from django.utils.functional import cached_property from django.utils import timezone -from django.core.validators import MaxValueValidator from django.utils.translation import ugettext_lazy as _l +from django.core.validators import MaxValueValidator, MinValueValidator from macaddress.fields import MACAddressField @@ -256,11 +256,26 @@ class IpType(RevMixin, AclMixin, models.Model): need_infra = models.BooleanField(default=False) domaine_ip_start = models.GenericIPAddressField(protocol='IPv4') domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4') + dnssec_reverse_v4 = models.BooleanField( + default=False, + help_text="Activer DNSSEC sur le reverse DNS IPv4", + ) prefix_v6 = models.GenericIPAddressField( protocol='IPv6', null=True, blank=True ) + prefix_v6_length = models.IntegerField( + default=64, + validators=[ + MaxValueValidator(128), + MinValueValidator(0) + ] + ) + dnssec_reverse_v6 = models.BooleanField( + default=False, + help_text="Activer DNSSEC sur le reverse DNS IPv6", + ) vlan = models.ForeignKey( 'Vlan', on_delete=models.PROTECT, @@ -294,6 +309,33 @@ class IpType(RevMixin, AclMixin, models.Model): """ Renvoie une liste des ip en string""" return [str(x) for x in self.ip_set] + @cached_property + def ip_set_full_info(self): + """Iter sur les range cidr, et renvoie network, broacast , etc""" + return [ + { + 'network': str(ip_set.network), + 'netmask': str(ip_set.netmask), + 'netmask_cidr': str(ip_set.prefixlen), + 'broadcast': str(ip_set.broadcast), + 'vlan': str(self.vlan), + 'vlan_id': self.vlan.vlan_id + } for ip_set in self.ip_set.iter_cidrs() + ] + + @cached_property + def ip6_set_full_info(self): + if self.prefix_v6: + return { + 'network' : str(self.prefix_v6), + 'netmask' : 'ffff:ffff:ffff:ffff::', + 'netmask_cidr' : str(self.prefix_v6_length), + 'vlan': str(self.vlan), + 'vlan_id': self.vlan.vlan_id + } + else: + return None + def ip_objects(self): """ Renvoie tous les objets ipv4 relié à ce type""" return IpList.objects.filter(ip_type=self) @@ -345,6 +387,17 @@ class IpType(RevMixin, AclMixin, models.Model): ): ipv6.check_and_replace_prefix(prefix=self.prefix_v6) + def get_associated_ptr_records(self): + from re2o.utils import all_active_assigned_interfaces + return (all_active_assigned_interfaces() + .filter(type__ip_type=self) + .filter(ipv4__isnull=False)) + + def get_associated_ptr_v6_records(self): + from re2o.utils import all_active_interfaces + return (all_active_interfaces(full=True) + .filter(type__ip_type=self)) + def clean(self): """ Nettoyage. Vérifie : - Que ip_stop est après ip_start diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index fa2a2767..7d4de6c5 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -34,11 +34,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,