diff --git a/docs_utils/re2o-archi.dia b/docs_utils/re2o-archi.dia new file mode 100644 index 00000000..1137480e Binary files /dev/null and b/docs_utils/re2o-archi.dia differ diff --git a/machines/forms.py b/machines/forms.py index 6112a182..eb16e2c9 100644 --- a/machines/forms.py +++ b/machines/forms.py @@ -156,7 +156,7 @@ class DelMachineTypeForm(Form): class IpTypeForm(ModelForm): class Meta: model = IpType - fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan'] + fields = ['type','extension','need_infra','domaine_ip_start','domaine_ip_stop', 'prefix_v6', 'vlan', 'ouverture_ports'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -165,7 +165,7 @@ class IpTypeForm(ModelForm): class EditIpTypeForm(IpTypeForm): class Meta(IpTypeForm.Meta): - fields = ['extension','type','need_infra', 'prefix_v6', 'vlan'] + fields = ['extension','type','need_infra', 'prefix_v6', 'vlan', 'ouverture_ports'] class DelIpTypeForm(Form): iptypes = forms.ModelMultipleChoiceField(queryset=IpType.objects.all(), label="Types d'ip actuelles", widget=forms.CheckboxSelectMultiple) diff --git a/machines/migrations/0060_iptype_ouverture_ports.py b/machines/migrations/0060_iptype_ouverture_ports.py new file mode 100644 index 00000000..e35f398f --- /dev/null +++ b/machines/migrations/0060_iptype_ouverture_ports.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-10-03 16:08 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0059_iptype_prefix_v6'), + ] + + operations = [ + migrations.AddField( + model_name='iptype', + name='ouverture_ports', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='machines.OuverturePortList'), + ), + ] diff --git a/machines/models.py b/machines/models.py index 698fdb90..7444996c 100644 --- a/machines/models.py +++ b/machines/models.py @@ -73,6 +73,7 @@ class IpType(models.Model): 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) + ouverture_ports = models.ForeignKey('OuverturePortList', blank=True, null=True) @cached_property def ip_range(self): diff --git a/machines/serializers.py b/machines/serializers.py index 2cf3d3e8..b18bbfb0 100644 --- a/machines/serializers.py +++ b/machines/serializers.py @@ -24,7 +24,7 @@ #Augustin Lemesle from rest_framework import serializers -from machines.models import Interface, IpType, Extension, IpList, MachineType, Domain, Text, Mx, Service_link, Ns +from machines.models import Interface, IpType, Extension, IpList, MachineType, Domain, Text, Mx, Service_link, Ns, OuverturePortList, OuverturePort class IpTypeField(serializers.RelatedField): def to_representation(self, value): @@ -81,10 +81,31 @@ class ExtensionNameField(serializers.RelatedField): class TypeSerializer(serializers.ModelSerializer): extension = ExtensionNameField(read_only=True) + ouverture_ports_tcp_in = serializers.SerializerMethodField('get_port_policy_input_tcp') + ouverture_ports_tcp_out = serializers.SerializerMethodField('get_port_policy_output_tcp') + ouverture_ports_udp_in = serializers.SerializerMethodField('get_port_policy_input_udp') + ouverture_ports_udp_out = serializers.SerializerMethodField('get_port_policy_output_udp') class Meta: model = IpType - fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop') + fields = ('type', 'extension', 'domaine_ip_start', 'domaine_ip_stop', 'ouverture_ports_tcp_in', 'ouverture_ports_tcp_out', 'ouverture_ports_udp_in', 'ouverture_ports_udp_out', ) + + def get_port_policy(self, obj, protocole, io): + if obj.ouverture_ports is None: + return [] + return map(str, obj.ouverture_ports.ouvertureport_set.filter(protocole=protocole).filter(io=io)) + + def get_port_policy_input_tcp(self, obj): + return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.IN) + + def get_port_policy_output_tcp(self, obj): + return self.get_port_policy(obj, OuverturePort.TCP, OuverturePort.OUT) + + def get_port_policy_input_udp(self, obj): + return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.IN) + + def get_port_policy_output_udp(self, obj): + return self.get_port_policy(obj, OuverturePort.UDP, OuverturePort.OUT) class ExtensionSerializer(serializers.ModelSerializer): origin = serializers.SerializerMethodField('get_origin_ip') @@ -185,3 +206,29 @@ class ServiceServersSerializer(serializers.ModelSerializer): def get_regen_status(self, obj): return obj.need_regen() + +class OuverturePortsSerializer(serializers.Serializer): + ipv4 = serializers.SerializerMethodField() + ipv6 = serializers.SerializerMethodField() + + def get_ipv4(): + return {i.ipv4.ipv4: + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv4 + } + + def get_ipv6(): + return {i.ipv6: + { + "tcp_in":[j.tcp_ports_in() for j in i.port_lists.all()], + "tcp_out":[j.tcp_ports_out()for j in i.port_lists.all()], + "udp_in":[j.udp_ports_in() for j in i.port_lists.all()], + "udp_out":[j.udp_ports_out() for j in i.port_lists.all()], + } + for i in Interface.objects.all() if i.ipv6 + } diff --git a/machines/templates/machines/aff_iptype.html b/machines/templates/machines/aff_iptype.html index aafc4c1d..454b169d 100644 --- a/machines/templates/machines/aff_iptype.html +++ b/machines/templates/machines/aff_iptype.html @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Fin Préfixe v6 Sur vlan + Ouverture ports par défault @@ -45,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ type.domaine_ip_stop }} {{ type.prefix_v6 }} {{ type.vlan }} + {{ type.ouverture_ports }} {% if is_infra %} {% include 'buttons/edit.html' with href='machines:edit-iptype' id=type.id %} diff --git a/machines/templates/machines/sidebar.html b/machines/templates/machines/sidebar.html index e635d69a..6ca3a07f 100644 --- a/machines/templates/machines/sidebar.html +++ b/machines/templates/machines/sidebar.html @@ -58,7 +58,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if is_cableur %} - Configuration de ports + Ouverture de ports {%endif%} {% endblock %} diff --git a/machines/urls.py b/machines/urls.py index 1ce5db7d..fa9b3497 100644 --- a/machines/urls.py +++ b/machines/urls.py @@ -93,6 +93,7 @@ urlpatterns = [ url(r'^rest/text/$', views.text, name='text'), url(r'^rest/zones/$', views.zones, name='zones'), url(r'^rest/service_servers/$', views.service_servers, name='service-servers'), + url(r'^rest/ouverture_ports/$', views.ouverture_ports, name='ouverture-ports'), url(r'index_portlist/$', views.index_portlist, name='index-portlist'), url(r'^edit_portlist/(?P[0-9]+)$', views.edit_portlist, name='edit-portlist'), url(r'^del_portlist/(?P[0-9]+)$', views.del_portlist, name='del-portlist'), diff --git a/machines/views.py b/machines/views.py index 3cc906c0..48adf44b 100644 --- a/machines/views.py +++ b/machines/views.py @@ -43,19 +43,81 @@ from django.contrib.auth import authenticate, login from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer -from machines.serializers import FullInterfaceSerializer, InterfaceSerializer, TypeSerializer, DomainSerializer, TextSerializer, MxSerializer, ExtensionSerializer, ServiceServersSerializer, NsSerializer +from machines.serializers import ( FullInterfaceSerializer, + InterfaceSerializer, + TypeSerializer, + DomainSerializer, + TextSerializer, + MxSerializer, + ExtensionSerializer, + ServiceServersSerializer, + NsSerializer, + OuverturePortsSerializer +) from reversion import revisions as reversion from reversion.models import Version import re -from .forms import NewMachineForm, EditMachineForm, EditInterfaceForm, AddInterfaceForm, MachineTypeForm, DelMachineTypeForm, ExtensionForm, DelExtensionForm, BaseEditInterfaceForm, BaseEditMachineForm -from .forms import EditIpTypeForm, IpTypeForm, DelIpTypeForm, DomainForm, AliasForm, DelAliasForm, NsForm, DelNsForm, TxtForm, DelTxtForm, MxForm, DelMxForm, VlanForm, DelVlanForm, ServiceForm, DelServiceForm, NasForm, DelNasForm +from .forms import ( + NewMachineForm, + EditMachineForm, + EditInterfaceForm, + AddInterfaceForm, + MachineTypeForm, + DelMachineTypeForm, + ExtensionForm, + DelExtensionForm, + BaseEditInterfaceForm, + BaseEditMachineForm +) +from .forms import ( + EditIpTypeForm, + IpTypeForm, + DelIpTypeForm, + DomainForm, + AliasForm, + DelAliasForm, + NsForm, + DelNsForm, + TxtForm, + DelTxtForm, + MxForm, + DelMxForm, + VlanForm, + DelVlanForm, + ServiceForm, + DelServiceForm, + NasForm, + DelNasForm +) from .forms import EditOuverturePortListForm, EditOuverturePortConfigForm -from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, OuverturePortList, OuverturePort +from .models import ( + IpType, + Machine, + Interface, + IpList, + MachineType, + Extension, + Mx, + Ns, + Domain, + Service, + Service_link, + Vlan, + Nas, + Text, + OuverturePortList, + OuverturePort +) from users.models import User from preferences.models import GeneralOption, OptionalMachine + from re2o.templatetags.massive_bootstrap_form import hidden_id, input_id -from re2o.utils import all_active_assigned_interfaces, all_has_access +from re2o.utils import ( + all_active_assigned_interfaces, + all_has_access, + filter_active_interfaces +) from re2o.views import form def f_type_id( is_type_tt ): @@ -72,7 +134,8 @@ def generate_ipv4_choices( form ) : choices = '{"":[{key:"",value:"Choisissez d\'abord un type de machine"},' mtype_id = -1 - for ip in f_ipv4.queryset.annotate(mtype_id=F('ip_type__machinetype__id')).order_by('mtype_id', 'id') : + for ip in f_ipv4.queryset.annotate(mtype_id=F('ip_type__machinetype__id'))\ + .order_by('mtype_id', 'id') : if mtype_id != ip.mtype_id : mtype_id = ip.mtype_id used_mtype_id.append(mtype_id) @@ -139,8 +202,8 @@ def generate_ipv4_mbf_param( form, is_type_tt ): @login_required def new_machine(request, userid): - """ Fonction de creation d'une machine. Cree l'objet machine, le sous objet interface et l'objet domain - à partir de model forms. + """ Fonction de creation d'une machine. Cree l'objet machine, + le sous objet interface et l'objet domain à partir de model forms. Trop complexe, devrait être simplifié""" try: user = User.objects.get(pk=userid) @@ -151,7 +214,9 @@ def new_machine(request, userid): max_lambdauser_interfaces = options.max_lambdauser_interfaces if not request.user.has_perms(('cableur',)): if user != request.user: - messages.error(request, "Vous ne pouvez pas ajouter une machine à un autre user que vous sans droit") + messages.error( + request, + "Vous ne pouvez pas ajouter une machine à un autre user que vous sans droit") return redirect("/users/profil/" + str(request.user.id)) if user.user_interfaces().count() >= max_lambdauser_interfaces: messages.error(request, "Vous avez atteint le maximum d'interfaces autorisées que vous pouvez créer vous même (%s) " % max_lambdauser_interfaces) @@ -1183,6 +1248,34 @@ def service_servers(request): @csrf_exempt @login_required @permission_required('serveur') +def ouverture_ports(request): + r = {'ipv4':{}, 'ipv6':{}} + for o in OuverturePortList.objects.all().prefetch_related('ouvertureport_set').prefetch_related('interface_set', 'interface_set__ipv4'): + pl = { + "tcp_in":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.IN))), + "tcp_out":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.OUT))), + "udp_in":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.IN))), + "udp_out":set(map(str,o.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.OUT))), + } + for i in filter_active_interfaces(o.interface_set): + if i.may_have_port_open(): + d = r['ipv4'].get(i.ipv4.ipv4, {}) + d["tcp_in"] = d.get("tcp_in",set()).union(pl["tcp_in"]) + d["tcp_out"] = d.get("tcp_out",set()).union(pl["tcp_out"]) + d["udp_in"] = d.get("udp_in",set()).union(pl["udp_in"]) + d["udp_out"] = d.get("udp_out",set()).union(pl["udp_out"]) + r['ipv4'][i.ipv4.ipv4] = d + if i.ipv6_object: + d = r['ipv6'].get(i.ipv6, {}) + d["tcp_in"] = d.get("tcp_in",set()).union(pl["tcp_in"]) + d["tcp_out"] = d.get("tcp_out",set()).union(pl["tcp_out"]) + d["udp_in"] = d.get("udp_in",set()).union(pl["udp_in"]) + d["udp_out"] = d.get("udp_out",set()).union(pl["udp_out"]) + r['ipv6'][i.ipv6] = d + return JSONResponse(r) +@csrf_exempt +@login_required +@permission_required('serveur') def regen_achieved(request): obj = Service_link.objects.filter(service__in=Service.objects.filter(service_type=request.POST['service']), server__in=Interface.objects.filter(domain__in=Domain.objects.filter(name=request.POST['server']))) if obj: diff --git a/re2o/utils.py b/re2o/utils.py index e2ca6db9..8abee181 100644 --- a/re2o/utils.py +++ b/re2o/utils.py @@ -104,9 +104,9 @@ def all_has_access(search_time=DT_NOW): ).distinct() -def all_active_interfaces(): - """Renvoie l'ensemble des machines autorisées à sortir sur internet """ - return Interface.objects.filter( +def filter_active_interfaces(interface_set): + """Filtre les machines autorisées à sortir sur internet dans une requête""" + return interface_set.filter( machine__in=Machine.objects.filter( user__in=all_has_access() ).filter(active=True) @@ -116,6 +116,11 @@ def all_active_interfaces(): .distinct() +def all_active_interfaces(): + """Renvoie l'ensemble des machines autorisées à sortir sur internet """ + return filter_active_interfaces(Interface.objects) + + def all_active_assigned_interfaces(): """ Renvoie l'ensemble des machines qui ont une ipv4 assignées et disposant de l'accès internet"""