diff --git a/machines/admin.py b/machines/admin.py
index 5fe4c49b..49b02a7e 100644
--- a/machines/admin.py
+++ b/machines/admin.py
@@ -26,7 +26,9 @@ from __future__ import unicode_literals
from django.contrib import admin
from reversion.admin import VersionAdmin
-from .models import IpType, Machine, MachineType, Domain, IpList, Interface, Extension, Mx, Ns, Vlan, Text, Nas, Service
+from .models import IpType, Machine, MachineType, Domain, IpList, Interface
+from .models import Extension, Mx, Ns, Vlan, Text, Nas, Service, OuverturePort
+from .models import OuverturePortList
class MachineAdmin(VersionAdmin):
pass
@@ -58,6 +60,12 @@ class NasAdmin(VersionAdmin):
class IpListAdmin(VersionAdmin):
pass
+class OuverturePortAdmin(VersionAdmin):
+ pass
+
+class OuverturePortListAdmin(VersionAdmin):
+ pass
+
class InterfaceAdmin(VersionAdmin):
list_display = ('machine','type','mac_address','ipv4','details')
@@ -80,3 +88,7 @@ admin.site.register(Domain, DomainAdmin)
admin.site.register(Service, ServiceAdmin)
admin.site.register(Vlan, VlanAdmin)
admin.site.register(Nas, NasAdmin)
+admin.site.register(OuverturePort, OuverturePortAdmin)
+admin.site.register(OuverturePortList, OuverturePortListAdmin)
+
+
diff --git a/machines/forms.py b/machines/forms.py
index 9f5a96ca..18631651 100644
--- a/machines/forms.py
+++ b/machines/forms.py
@@ -22,9 +22,11 @@
from __future__ import unicode_literals
+import re
+
from django.forms import ModelForm, Form, ValidationError
from django import forms
-from .models import Domain, Machine, Interface, IpList, MachineType, Extension, Mx, Text, Ns, Service, Vlan, Nas, IpType
+from .models import Domain, Machine, Interface, IpList, MachineType, Extension, Mx, Text, Ns, Service, Vlan, Nas, IpType, OuverturePortList, OuverturePort
from django.db.models import Q
from django.core.validators import validate_email
@@ -50,7 +52,8 @@ class BaseEditMachineForm(EditMachineForm):
class EditInterfaceForm(ModelForm):
class Meta:
model = Interface
- fields = '__all__'
+ # fields = '__all__'
+ exclude = ['port_lists']
def __init__(self, *args, **kwargs):
super(EditInterfaceForm, self).__init__(*args, **kwargs)
@@ -142,7 +145,7 @@ class DelMachineTypeForm(Form):
class IpTypeForm(ModelForm):
class Meta:
model = IpType
- fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'vlan']
+ fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan']
def __init__(self, *args, **kwargs):
@@ -151,7 +154,7 @@ class IpTypeForm(ModelForm):
class EditIpTypeForm(IpTypeForm):
class Meta(IpTypeForm.Meta):
- fields = ['extension','type','need_infra', 'vlan']
+ fields = ['extension','type','need_infra', 'prefix_v6', 'vlan']
class DelIpTypeForm(Form):
iptypes = forms.ModelMultipleChoiceField(queryset=IpType.objects.all(), label="Types d'ip actuelles", widget=forms.CheckboxSelectMultiple)
@@ -232,5 +235,13 @@ class VlanForm(ModelForm):
class DelVlanForm(Form):
vlan = forms.ModelMultipleChoiceField(queryset=Vlan.objects.all(), label="Vlan actuels", widget=forms.CheckboxSelectMultiple)
+class EditOuverturePortConfigForm(ModelForm):
+ class Meta:
+ model = Interface
+ fields = ['port_lists']
+class EditOuverturePortListForm(ModelForm):
+ class Meta:
+ model = OuverturePortList
+ fields = '__all__'
diff --git a/machines/migrations/0058_auto_20171002_0350.py b/machines/migrations/0058_auto_20171002_0350.py
new file mode 100644
index 00000000..bc6b2508
--- /dev/null
+++ b/machines/migrations/0058_auto_20171002_0350.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-10-02 01:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0057_nas_autocapture_mac'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OuverturePort',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('begin', models.IntegerField()),
+ ('end', models.IntegerField()),
+ ('protocole', models.CharField(choices=[('T', 'TCP'), ('U', 'UDP')], default='T', max_length=1)),
+ ('io', models.CharField(choices=[('I', 'IN'), ('O', 'OUT')], default='O', max_length=1)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='OuverturePortList',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(help_text='Nom de la configuration des ports.', max_length=255)),
+ ],
+ ),
+ migrations.AddField(
+ model_name='ouvertureport',
+ name='port_list',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.OuverturePortList'),
+ ),
+ migrations.AddField(
+ model_name='interface',
+ name='port_lists',
+ field=models.ManyToManyField(blank=True, to='machines.OuverturePortList'),
+ ),
+ ]
diff --git a/machines/migrations/0059_iptype_prefix_v6.py b/machines/migrations/0059_iptype_prefix_v6.py
new file mode 100644
index 00000000..464fc5e6
--- /dev/null
+++ b/machines/migrations/0059_iptype_prefix_v6.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-10-02 16:33
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('machines', '0058_auto_20171002_0350'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='iptype',
+ name='prefix_v6',
+ field=models.GenericIPAddressField(blank=True, null=True, protocol='IPv6'),
+ ),
+ ]
diff --git a/machines/models.py b/machines/models.py
index 8eff89fc..8e7b1c3c 100644
--- a/machines/models.py
+++ b/machines/models.py
@@ -70,6 +70,7 @@ class IpType(models.Model):
need_infra = models.BooleanField(default=False)
domaine_ip_start = models.GenericIPAddressField(protocol='IPv4')
domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4')
+ prefix_v6 = models.GenericIPAddressField(protocol='IPv6', null=True, blank=True)
vlan = models.ForeignKey('Vlan', on_delete=models.PROTECT, blank=True, null=True)
@cached_property
@@ -122,6 +123,9 @@ class IpType(models.Model):
for element in IpType.objects.all().exclude(pk=self.pk):
if not self.ip_set.isdisjoint(element.ip_set):
raise ValidationError("Le range indiqué n'est pas disjoint des ranges existants")
+ # On formate le prefix v6
+ if self.prefix_v6:
+ self.prefix_v6 = str(IPNetwork(self.prefix_v6 + '/64').network)
return
def save(self, *args, **kwargs):
@@ -218,11 +222,11 @@ class Interface(models.Model):
PRETTY_NAME = "Interface"
ipv4 = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True)
- #ipv6 = models.GenericIPAddressField(protocol='IPv6', null=True)
mac_address = MACAddressField(integer=False, unique=True)
machine = models.ForeignKey('Machine', on_delete=models.CASCADE)
type = models.ForeignKey('MachineType', on_delete=models.PROTECT)
details = models.CharField(max_length=255, blank=True)
+ port_lists = models.ManyToManyField('OuverturePortList', blank=True)
@cached_property
def is_active(self):
@@ -231,6 +235,18 @@ class Interface(models.Model):
user = self.machine.user
return machine.active and user.has_access()
+
+ @cached_property
+ def ipv6_object(self):
+ if self.type.ip_type.prefix_v6:
+ return EUI(self.mac_address).ipv6(IPNetwork(self.type.ip_type.prefix_v6).network)
+ else:
+ return None
+
+ @cached_property
+ def ipv6(self):
+ return str(self.ipv6_object)
+
def mac_bare(self):
return str(EUI(self.mac_address, dialect=mac_bare)).lower()
@@ -278,6 +294,15 @@ class Interface(models.Model):
domain = None
return str(domain)
+ def has_private_ip(self):
+ if self.ipv4:
+ return IPAddress(str(self.ipv4)).is_private()
+ else:
+ return False
+
+ def may_have_port_open(self):
+ return self.ipv4 and not self.has_private_ip()
+
class Domain(models.Model):
PRETTY_NAME = "Domaine dns"
@@ -406,6 +431,67 @@ class Service_link(models.Model):
def __str__(self):
return str(self.server) + " " + str(self.service)
+
+class OuverturePortList(models.Model):
+ """Liste des ports ouverts sur une interface."""
+ name = models.CharField(help_text="Nom de la configuration des ports.", max_length=255)
+
+ def __str__(self):
+ return self.name
+
+ def tcp_ports_in(self):
+ return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.IN)
+
+ def udp_ports_in(self):
+ return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.IN)
+
+ def tcp_ports_out(self):
+ return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.OUT)
+
+ def udp_ports_out(self):
+ return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.OUT)
+
+
+class OuverturePort(models.Model):
+ """
+ Représente un simple port ou une plage de ports.
+
+ Les ports de la plage sont compris entre begin et en inclus.
+ Si begin == end alors on ne représente qu'un seul port.
+ """
+ TCP = 'T'
+ UDP = 'U'
+ IN = 'I'
+ OUT = 'O'
+ begin = models.IntegerField()
+ end = models.IntegerField()
+ port_list = models.ForeignKey('OuverturePortList', on_delete=models.CASCADE)
+ protocole = models.CharField(
+ max_length=1,
+ choices=(
+ (TCP, 'TCP'),
+ (UDP, 'UDP'),
+ ),
+ default=TCP,
+ )
+ io = models.CharField(
+ max_length=1,
+ choices=(
+ (IN, 'IN'),
+ (OUT, 'OUT'),
+ ),
+ default=OUT,
+ )
+
+ def __str__(self):
+ if self.begin == self.end :
+ return str(self.begin)
+ return '-'.join([str(self.begin), str(self.end)])
+
+ def show_port(self):
+ return str(self)
+
+
@receiver(post_save, sender=Machine)
def machine_post_save(sender, **kwargs):
user = kwargs['instance'].user
@@ -426,6 +512,9 @@ def interface_post_save(sender, **kwargs):
interface = kwargs['instance']
user = interface.machine.user
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
+ if not interface.may_have_port_open() and interface.port_lists.all():
+ interface.port_lists.clear()
+ # Regen services
regen('dhcp')
regen('mac_ip_list')
diff --git a/machines/serializers.py b/machines/serializers.py
index bfe5f295..51daa4b5 100644
--- a/machines/serializers.py
+++ b/machines/serializers.py
@@ -55,6 +55,25 @@ class InterfaceSerializer(serializers.ModelSerializer):
def get_macaddress(self, obj):
return str(obj.mac_address)
+class FullInterfaceSerializer(serializers.ModelSerializer):
+ ipv4 = IpListSerializer(read_only=True)
+ mac_address = serializers.SerializerMethodField('get_macaddress')
+ domain = serializers.SerializerMethodField('get_dns')
+ extension = serializers.SerializerMethodField('get_interface_extension')
+
+ class Meta:
+ model = Interface
+ fields = ('ipv4', 'ipv6', 'mac_address', 'domain', 'extension')
+
+ def get_dns(self, obj):
+ return obj.domain.name
+
+ def get_interface_extension(self, obj):
+ return obj.domain.extension.name
+
+ def get_macaddress(self, obj):
+ return str(obj.mac_address)
+
class ExtensionNameField(serializers.RelatedField):
def to_representation(self, value):
return value.name
diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html
index 46318c83..aafc4c1d 100644
--- a/machines/templates/machines/aff_iptype.html
+++ b/machines/templates/machines/aff_iptype.html
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Nécessite l'autorisation infra
Début
Fin
+
Préfixe v6
Sur vlan
@@ -42,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ type.need_infra }}
{{ type.domaine_ip_start }}
{{ type.domaine_ip_stop }}
+
{{ type.prefix_v6 }}
{{ type.vlan }}
{% if is_infra %}
diff --git a/machines/templates/machines/aff_machines.html b/machines/templates/machines/aff_machines.html
index a09d8868..c22de7c9 100644
--- a/machines/templates/machines/aff_machines.html
+++ b/machines/templates/machines/aff_machines.html
@@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Nom dns
Type
Mac
-
Ipv4
+
IP
@@ -74,7 +74,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,