2017-09-10 14:53:02 +00:00
# -*- mode: python; coding: utf-8 -*-
2020-11-23 16:06:37 +00:00
# Re2o est un logiciel d'administration développé initiallement au Rézo Metz. Il
2017-01-15 23:01:18 +00:00
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
2018-07-22 18:43:38 +00:00
# Copyright © 2016-2018 Gabriel Détraz
2019-09-29 14:02:28 +00:00
# Copyright © 2017 Lara Kermarec
2017-01-15 23:01:18 +00:00
# Copyright © 2017 Augustin Lemesle
2018-07-22 18:43:38 +00:00
# Copyright © 2018 Charlie Jacomme
2017-01-15 23:01:18 +00:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2018-04-14 18:19:02 +00:00
""" machines.models
The models definitions for the Machines app
"""
2017-01-15 23:01:18 +00:00
2017-09-10 23:29:24 +00:00
from __future__ import unicode_literals
2018-09-24 17:31:23 +00:00
import base64
import hashlib
2017-10-15 20:10:33 +00:00
import re
2018-09-24 17:31:23 +00:00
from datetime import timedelta
2018-01-30 03:51:15 +00:00
from ipaddress import IPv6Address
2018-04-02 01:52:15 +00:00
from itertools import chain
2017-10-15 20:10:33 +00:00
2018-09-24 17:31:23 +00:00
from django . core . validators import MaxValueValidator , MinValueValidator
2016-07-02 22:27:22 +00:00
from django . db import models
2018-06-24 13:59:04 +00:00
from django . db . models import Q
2017-10-15 20:10:33 +00:00
from django . db . models . signals import post_save , post_delete
2016-07-25 21:54:40 +00:00
from django . dispatch import receiver
2016-07-06 20:49:16 +00:00
from django . forms import ValidationError
2017-08-08 04:56:19 +00:00
from django . utils import timezone
2019-03-17 03:46:55 +00:00
from django . db import transaction
from reversion import revisions as reversion
2018-09-24 17:31:23 +00:00
from django . utils . functional import cached_property
2018-08-05 16:48:22 +00:00
from django . utils . translation import ugettext_lazy as _
2018-11-03 18:24:46 +00:00
from macaddress . fields import MACAddressField , default_dialect
2019-11-04 16:55:03 +00:00
from netaddr import (
mac_bare ,
EUI ,
NotRegisteredError ,
IPSet ,
IPRange ,
IPNetwork ,
IPAddress ,
)
2016-07-02 22:27:22 +00:00
2018-09-24 17:31:23 +00:00
import preferences . models
import users . models
2021-01-12 18:08:17 +00:00
import users . signals
2017-12-30 00:48:23 +00:00
from re2o . field_permissions import FieldPermissionModelMixin
2018-04-13 22:48:44 +00:00
from re2o . mixins import AclMixin , RevMixin
2017-12-30 00:48:23 +00:00
2017-08-08 17:40:30 +00:00
2020-04-30 20:27:21 +00:00
class Machine ( RevMixin , FieldPermissionModelMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Machine.
Attributes :
user : the user who owns the machine .
name : the name of the machine .
active : whether the machine is active .
"""
2019-11-04 16:55:03 +00:00
user = models . ForeignKey ( " users.User " , on_delete = models . CASCADE )
2017-10-15 20:10:33 +00:00
name = models . CharField (
2019-11-16 14:07:15 +00:00
max_length = 255 , help_text = _ ( " Optional. " ) , blank = True , null = True
2017-10-15 20:10:33 +00:00
)
2016-07-05 10:21:43 +00:00
active = models . BooleanField ( default = True )
2016-07-02 22:27:22 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_machine " , _ ( " Can view a machine object " ) ) ,
2019-11-04 16:55:03 +00:00
( " change_machine_user " , _ ( " Can change the user of a machine " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " machine " )
verbose_name_plural = _ ( " machines " )
2017-12-31 18:47:22 +00:00
2018-04-02 01:52:15 +00:00
def linked_objects ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the related interface and domain. """
2018-04-13 22:48:44 +00:00
return chain (
self . interface_set . all ( ) ,
2019-11-04 16:55:03 +00:00
Domain . objects . filter ( interface_parent__in = self . interface_set . all ( ) ) ,
2018-04-13 22:48:44 +00:00
)
2018-04-02 01:52:15 +00:00
2017-12-30 00:48:23 +00:00
@staticmethod
2018-04-14 18:19:02 +00:00
def can_change_user ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if an user is allowed to change the user who owns a
2017-12-30 00:48:23 +00:00
Machine .
Args :
2020-04-29 22:17:01 +00:00
user_request : the user requesting to change owner .
2017-12-30 00:48:23 +00:00
Returns :
A tuple with a boolean stating if edition is allowed and an
explanation message .
"""
2019-11-04 16:55:03 +00:00
can = user_request . has_perm ( " machines.change_machine_user " )
2019-09-06 12:14:33 +00:00
return (
2019-09-09 12:40:40 +00:00
can ,
2019-11-04 16:55:03 +00:00
_ ( " You don ' t have the right to change the machine ' s user. " )
if not can
else None ,
( " machines.change_machine_user " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-12-30 00:48:23 +00:00
2018-04-14 18:19:02 +00:00
@staticmethod
def can_view_all ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can view all machines.
Args :
user_request : the user requesting to view the machines .
Returns :
A tuple indicating whether the user can view all machines and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.view_machine " ) :
2019-09-06 12:14:33 +00:00
return (
False ,
_ ( " You don ' t have the right to view all the machines. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.view_machine " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2018-03-28 15:15:29 +00:00
2018-04-14 18:19:02 +00:00
@staticmethod
def can_create ( user_request , userid , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can create the machine, did not reach his quota
and create a machine for themselves .
Args :
user_request : the user requesting to create the machine .
userid : the ID of the owner of the machine to be created .
Returns :
A tuple indicating whether the user can create the machine and a
message if not .
"""
2017-11-28 22:33:47 +00:00
try :
2017-11-30 20:38:16 +00:00
user = users . models . User . objects . get ( pk = userid )
2017-11-28 22:33:47 +00:00
except users . models . User . DoesNotExist :
2019-09-06 12:14:33 +00:00
return False , _ ( " Nonexistent user. " ) , None
2019-11-04 16:55:03 +00:00
max_lambdauser_interfaces = preferences . models . OptionalMachine . get_cached_value (
" max_lambdauser_interfaces "
)
if not user_request . has_perm ( " machines.add_machine " ) :
if not (
preferences . models . OptionalMachine . get_cached_value ( " create_machine " )
) :
2019-09-06 12:14:33 +00:00
return (
False ,
_ ( " You don ' t have the right to add a machine. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.add_machine " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-11-28 22:33:47 +00:00
if user != user_request :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:27:21 +00:00
_ ( " You don ' t have the right to add a machine to another " " user. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.add_machine " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-11-28 22:33:47 +00:00
if user . user_interfaces ( ) . count ( ) > = max_lambdauser_interfaces :
2019-11-04 16:55:03 +00:00
return (
False ,
_ (
" You reached the maximum number of interfaces "
" that you are allowed to create yourself "
" ( %s ). " % max_lambdauser_interfaces
) ,
None ,
)
2019-09-06 12:14:33 +00:00
return True , None , None
2017-11-28 22:33:47 +00:00
2017-11-30 20:48:32 +00:00
def can_edit ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can edit the current instance of Machine (self).
Args :
user_request : the user requesting to edit self .
Returns :
A tuple indicating whether the user can edit self and a
message if not .
"""
2018-01-08 00:21:24 +00:00
if self . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . user . can_edit (
2019-11-04 16:55:03 +00:00
self . user , user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2019-11-04 16:55:03 +00:00
if not ( user_request . has_perm ( " machines.change_interface " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:27:21 +00:00
_ ( " You don ' t have the right to edit a machine of another " " user. " ) ,
2020-04-30 20:32:17 +00:00
( " machines.change_interface " , ) + ( permissions or ( ) ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-11 21:02:32 +00:00
2017-12-03 15:32:43 +00:00
def can_delete ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can delete the current instance of Machine (self).
Args :
user_request : the user requesting to delete self .
Returns :
A tuple indicating whether the user can delete self and a
message if not .
"""
2018-01-08 00:21:24 +00:00
if self . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . user . can_edit (
2019-11-04 16:55:03 +00:00
self . user , user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2020-04-30 20:21:12 +00:00
if not ( user_request . has_perm ( " machines.delete_interface " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You don ' t have the right to delete a machine "
" of another user. "
) ,
2020-04-30 20:32:17 +00:00
( " machines.change_interface " , ) + ( permissions or ( ) ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 15:32:43 +00:00
2018-04-14 18:19:02 +00:00
def can_view ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can view the current instance of Machine (self).
Args :
user_request : the user requesting to view self .
Returns :
A tuple indicating whether the user can view self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.view_machine " )
and self . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:27:21 +00:00
_ ( " You don ' t have the right to view other machines than " " yours. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.view_machine " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 16:43:07 +00:00
2018-06-24 13:59:04 +00:00
@cached_property
def short_name ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the short name of the machine.
By default , get the name of the first interface of the machine .
"""
2018-10-15 17:57:27 +00:00
interfaces_set = self . interface_set . first ( )
if interfaces_set :
return str ( interfaces_set . domain . name )
else :
2019-01-08 23:39:31 +00:00
return _ ( " No name " )
2018-06-24 13:59:04 +00:00
2018-07-09 19:06:21 +00:00
@cached_property
def complete_name ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete name of the machine.
By default , get the name of the first interface of the machine .
"""
2018-07-09 19:06:21 +00:00
return str ( self . interface_set . first ( ) )
2018-06-24 13:59:04 +00:00
@cached_property
def all_short_names ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the short names of all interfaces of the machine. """
2019-11-04 16:55:03 +00:00
return (
Domain . objects . filter ( interface_parent__machine = self )
. values_list ( " name " , flat = True )
. distinct ( )
)
2018-06-24 13:59:04 +00:00
2018-10-14 22:58:46 +00:00
@cached_property
def get_name ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the name of the machine.
The name can be provided by the user , else the short name is used .
"""
2018-10-14 22:58:46 +00:00
return self . name or self . short_name
2019-03-17 16:56:46 +00:00
@classmethod
def mass_delete ( cls , machine_queryset ) :
2020-04-29 22:17:01 +00:00
""" Mass delete for machine queryset. """
2019-09-29 15:57:10 +00:00
from topologie . models import AccessPoint
2019-11-04 16:55:03 +00:00
Domain . objects . filter (
cname__interface_parent__machine__in = machine_queryset
) . _raw_delete ( machine_queryset . db )
Domain . objects . filter (
interface_parent__machine__in = machine_queryset
) . _raw_delete ( machine_queryset . db )
Ipv6List . objects . filter ( interface__machine__in = machine_queryset ) . _raw_delete (
machine_queryset . db
)
Interface . objects . filter ( machine__in = machine_queryset ) . filter (
port_lists__isnull = False
) . delete ( )
Interface . objects . filter ( machine__in = machine_queryset ) . _raw_delete (
machine_queryset . db
)
AccessPoint . objects . filter ( machine_ptr__in = machine_queryset ) . _raw_delete (
machine_queryset . db
)
2019-03-17 16:56:46 +00:00
machine_queryset . _raw_delete ( machine_queryset . db )
2018-06-24 13:59:04 +00:00
@cached_property
def all_complete_names ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete names of all interfaces of the machine. """
2019-11-04 16:55:03 +00:00
return [
str ( domain )
for domain in Domain . objects . filter (
Q ( cname__interface_parent__machine = self )
| Q ( interface_parent__machine = self )
)
]
2018-06-24 13:59:04 +00:00
2018-01-08 22:57:19 +00:00
def __init__ ( self , * args , * * kwargs ) :
super ( Machine , self ) . __init__ ( * args , * * kwargs )
2019-11-04 16:55:03 +00:00
self . field_permissions = { " user " : self . can_change_user }
2018-01-08 22:57:19 +00:00
2016-07-02 22:27:22 +00:00
def __str__ ( self ) :
2020-06-01 09:24:23 +00:00
return str ( self . user ) + " - " + str ( self . id ) + " - " + str ( self . get_name )
2017-10-15 20:10:33 +00:00
2018-07-29 11:40:49 +00:00
2018-03-31 15:18:39 +00:00
class MachineType ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Machine type, related to an IP type and assigned to interfaces.
Attributes :
name : the name of the machine type .
ip_type : the IP type of the machine type .
"""
2019-11-04 16:55:03 +00:00
2019-03-03 16:28:33 +00:00
name = models . CharField ( max_length = 255 )
2017-10-15 20:10:33 +00:00
ip_type = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" IpType " , on_delete = models . PROTECT , blank = True , null = True
2017-10-15 20:10:33 +00:00
)
2016-10-22 22:55:58 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_machinetype " , _ ( " Can view a machine type object " ) ) ,
( " use_all_machinetype " , _ ( " Can use all machine types " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " machine type " )
verbose_name_plural = _ ( " machine types " )
2017-12-31 18:47:22 +00:00
2017-07-23 03:03:56 +00:00
def all_interfaces ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all interfaces of the current machine type (self). """
2019-03-03 16:28:33 +00:00
return Interface . objects . filter ( machine_type = self )
2017-07-23 03:03:56 +00:00
2020-06-09 21:23:48 +00:00
def update_domains ( self ) :
2020-06-09 21:30:52 +00:00
""" Update domains extension with the extension of interface_parent. Called after update of an ip_type or a machine_type object. Exceptions are handled in the views.
( Calling domain . clear ( ) for all domains could take several minutes )
"""
2020-06-09 21:23:48 +00:00
Domain . objects . filter ( interface_parent__machine_type = self ) . update ( extension = self . ip_type . extension )
2018-04-14 18:19:02 +00:00
@staticmethod
def can_use_all ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if an user can use all machine types.
2017-12-30 00:48:23 +00:00
Args :
2020-04-29 22:17:01 +00:00
user_request : the user requesting to use all machine types .
2017-12-30 00:48:23 +00:00
Returns :
2020-04-29 22:17:01 +00:00
A tuple with a boolean stating if user can access and an explanation
2017-12-30 00:48:23 +00:00
message is acces is not allowed .
"""
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.use_all_machinetype " ) :
2019-09-06 12:14:33 +00:00
return (
False ,
_ ( " You don ' t have the right to use all machine types. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.use_all_machinetype " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-30 00:48:23 +00:00
2020-12-31 13:55:10 +00:00
@classmethod
def can_list ( cls , user_request , * _args , * * _kwargs ) :
""" All users can list unprivileged machinetypes
Only members of privileged groups can list all .
: param user_request : The user who wants to view the list .
: return : True if the user can view the list and an explanation
message .
"""
can , _message , _group = cls . can_use_all ( user_request )
if can :
return (
True ,
None ,
None ,
cls . objects . all ( )
)
else :
return (
2021-01-02 22:03:13 +00:00
True ,
2020-12-31 13:55:10 +00:00
_ ( " You don ' t have the right to use all machine types. " ) ,
( " machines.use_all_machinetype " , ) ,
cls . objects . filter (
ip_type__in = IpType . objects . filter ( need_infra = False )
) ,
)
2016-10-22 22:55:58 +00:00
def __str__ ( self ) :
2019-03-03 16:28:33 +00:00
return self . name
2017-10-15 20:10:33 +00:00
2016-10-22 22:55:58 +00:00
2018-03-31 15:18:39 +00:00
class IpType ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" IP type, defining an IP range and assigned to machine types.
Attributes :
name : the name of the IP type .
extension : the extension related to the IP type .
need_infra : whether the ' infra ' right is required .
domaine_ip_start : the start IPv4 address of the IP type .
domaine_ip_stop : the stop IPv4 address of the IP type .
domaine_ip_network : the IPv4 network containg the IP range ( optional ) .
domaine_ip_netmask : the netmask of the domain ' s IPv4 range.
reverse_v4 : whether reverse DNS is enabled for IPv4 .
prefix_v6 : the IPv6 prefix .
prefix_v6_length : the IPv6 prefix length .
reverse_v6 : whether reverse DNS is enabled for IPv6 .
vlan : the VLAN related to the IP type .
ouverture_ports : the ports opening list related to the IP type .
"""
2019-11-04 16:55:03 +00:00
2019-03-03 16:28:33 +00:00
name = models . CharField ( max_length = 255 )
2019-11-04 16:55:03 +00:00
extension = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2016-10-13 00:11:23 +00:00
need_infra = models . BooleanField ( default = False )
2019-11-04 16:55:03 +00:00
domaine_ip_start = models . GenericIPAddressField ( protocol = " IPv4 " )
domaine_ip_stop = models . GenericIPAddressField ( protocol = " IPv4 " )
2018-08-06 22:10:54 +00:00
domaine_ip_network = models . GenericIPAddressField (
2019-11-04 16:55:03 +00:00
protocol = " IPv4 " ,
2018-08-06 22:10:54 +00:00
null = True ,
blank = True ,
2019-11-16 14:07:15 +00:00
help_text = _ ( " Network containing the domain ' s IPv4 range (optional). " ) ,
2018-08-06 22:10:54 +00:00
)
domaine_ip_netmask = models . IntegerField (
default = 24 ,
2019-11-04 16:55:03 +00:00
validators = [ MaxValueValidator ( 31 ) , MinValueValidator ( 8 ) ] ,
2019-11-16 14:07:15 +00:00
help_text = _ ( " Netmask for the domain ' s IPv4 range. " ) ,
2018-08-06 22:10:54 +00:00
)
2018-08-07 07:52:00 +00:00
reverse_v4 = models . BooleanField (
2019-11-16 14:07:15 +00:00
default = False , help_text = _ ( " Enable reverse DNS for IPv4. " )
2017-10-15 20:10:33 +00:00
)
2019-11-04 16:55:03 +00:00
prefix_v6 = models . GenericIPAddressField ( protocol = " IPv6 " , null = True , blank = True )
2018-07-16 18:52:39 +00:00
prefix_v6_length = models . IntegerField (
2019-11-04 16:55:03 +00:00
default = 64 , validators = [ MaxValueValidator ( 128 ) , MinValueValidator ( 0 ) ]
2018-09-24 17:31:23 +00:00
)
2018-08-07 07:52:00 +00:00
reverse_v6 = models . BooleanField (
2019-11-16 14:07:15 +00:00
default = False , help_text = _ ( " Enable reverse DNS for IPv6. " )
2017-10-15 20:10:33 +00:00
)
2019-11-04 16:55:03 +00:00
vlan = models . ForeignKey ( " Vlan " , on_delete = models . PROTECT , blank = True , null = True )
ouverture_ports = models . ForeignKey ( " OuverturePortList " , blank = True , null = True )
2016-07-02 22:27:22 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_iptype " , _ ( " Can view an IP type object " ) ) ,
( " use_all_iptype " , _ ( " Can use all IP types " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " IP type " )
2019-01-08 23:39:31 +00:00
verbose_name_plural = _ ( " IP types " )
2017-12-31 18:47:22 +00:00
2017-07-21 03:06:53 +00:00
@cached_property
2017-08-28 22:35:03 +00:00
def ip_range ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the IPRange object from the current IP type. """
2017-10-15 20:10:33 +00:00
return IPRange ( self . domaine_ip_start , end = self . domaine_ip_stop )
2017-07-21 03:06:53 +00:00
@cached_property
def ip_set ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the IPSet object from the current IP type. """
2017-08-28 22:35:03 +00:00
return IPSet ( self . ip_range )
2017-07-21 03:06:53 +00:00
@cached_property
def ip_set_as_str ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of the IP addresses in the range as strings. """
2017-07-21 03:06:53 +00:00
return [ str ( x ) for x in self . ip_set ]
2018-08-06 22:10:54 +00:00
@cached_property
def ip_set_cidrs_as_str ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of CIDRs from the IP range. """
2018-08-06 22:10:54 +00:00
return [ str ( ip_range ) for ip_range in self . ip_set . iter_cidrs ( ) ]
2018-07-16 18:52:39 +00:00
@cached_property
def ip_set_full_info ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the set of all information for IPv4.
Iter over the CIDRs and get the network , broadcast etc .
"""
2018-07-16 18:52:39 +00:00
return [
{
2019-11-04 16:55:03 +00:00
" 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 ( )
2018-07-16 18:52:39 +00:00
]
@cached_property
def ip6_set_full_info ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the set of all information for IPv6. """
2018-07-16 18:52:39 +00:00
if self . prefix_v6 :
return {
2019-11-04 16:55:03 +00:00
" 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 ,
2018-07-16 18:52:39 +00:00
}
else :
return None
2018-08-06 22:10:54 +00:00
@cached_property
def ip_network ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the parent IP network of the range, if specified. """
2018-08-06 22:10:54 +00:00
if self . domaine_ip_network :
2019-11-04 16:55:03 +00:00
return IPNetwork (
str ( self . domaine_ip_network ) + " / " + str ( self . domaine_ip_netmask )
)
2018-08-06 22:10:54 +00:00
return None
@cached_property
def ip_net_full_info ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all information on the network including the range. """
2019-10-10 15:55:59 +00:00
if self . ip_network :
return {
2019-11-04 16:55:03 +00:00
" network " : str ( self . ip_network . network ) ,
" netmask " : str ( self . ip_network . netmask ) ,
" broadcast " : str ( self . ip_network . broadcast ) ,
" netmask_cidr " : str ( self . ip_network . prefixlen ) ,
" vlan " : str ( self . vlan ) ,
" vlan_id " : self . vlan . vlan_id ,
2019-10-10 15:55:59 +00:00
}
else :
return None
2018-08-06 22:10:54 +00:00
2018-08-05 09:14:19 +00:00
@cached_property
def complete_prefixv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete prefix v6 as CIDR. """
2018-08-05 09:14:19 +00:00
return str ( self . prefix_v6 ) + " / " + str ( self . prefix_v6_length )
2017-07-21 03:06:53 +00:00
def ip_objects ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all IPv4 objects related to the current IP type. """
2017-07-21 04:49:39 +00:00
return IpList . objects . filter ( ip_type = self )
def free_ip ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all free IP addresses related to the current IP type. """
2019-11-04 16:55:03 +00:00
return IpList . objects . filter ( interface__isnull = True ) . filter ( ip_type = self )
2017-07-21 03:06:53 +00:00
def gen_ip_range ( self ) :
2020-04-29 22:17:01 +00:00
""" Create the IpList objects related to the current IP type.
Goes through the IP addresses on by one . If they already exist , update the
type related to the IP addresses .
"""
# Creation of the IP range in the IpList objects
2018-06-22 15:48:10 +00:00
ip_obj = [ IpList ( ip_type = self , ipv4 = str ( ip ) ) for ip in self . ip_range ]
2019-11-04 16:55:03 +00:00
listes_ip = IpList . objects . filter ( ipv4__in = [ str ( ip ) for ip in self . ip_range ] )
2020-04-29 22:17:01 +00:00
# If there are no IP addresses, create them
2017-08-28 23:04:15 +00:00
if not listes_ip :
IpList . objects . bulk_create ( ip_obj )
2020-04-29 22:17:01 +00:00
# Else, up the IP type
2017-08-28 23:04:15 +00:00
else :
listes_ip . update ( ip_type = self )
2017-08-23 21:26:49 +00:00
return
2017-07-21 03:06:53 +00:00
def del_ip_range ( self ) :
2020-04-29 22:17:01 +00:00
""" Deprecated method.
Delete the IP range and the IpList in cascade .
"""
2017-07-21 04:49:39 +00:00
if Interface . objects . filter ( ipv4__in = self . ip_objects ( ) ) :
2019-11-04 16:55:03 +00:00
raise ValidationError (
_ (
" One or several IP addresses from the "
" range are affected, impossible to delete "
" the range. "
)
)
2017-07-21 03:06:53 +00:00
for ip in self . ip_objects ( ) :
ip . delete ( )
2018-01-30 03:51:15 +00:00
def check_replace_prefixv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Replace the IPv6 prefixes of the interfaces related to the current
IP type .
"""
2018-01-30 03:51:15 +00:00
if not self . prefix_v6 :
return
else :
2018-04-13 22:48:44 +00:00
for ipv6 in Ipv6List . objects . filter (
2019-11-04 16:55:03 +00:00
interface__in = Interface . objects . filter (
machine_type__in = MachineType . objects . filter ( ip_type = self )
)
2018-07-17 19:26:42 +00:00
) :
2018-01-30 03:51:15 +00:00
ipv6 . check_and_replace_prefix ( prefix = self . prefix_v6 )
2018-07-14 08:59:17 +00:00
def get_associated_ptr_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the PTR records related to the current IP type, if reverse DNS
is enabled for IPv4 .
"""
2018-07-14 08:59:17 +00:00
from re2o . utils import all_active_assigned_interfaces
2019-11-04 16:55:03 +00:00
2018-08-07 07:57:59 +00:00
if self . reverse_v4 :
2019-11-04 16:55:03 +00:00
return (
all_active_assigned_interfaces ( )
. filter ( machine_type__ip_type = self )
. filter ( ipv4__isnull = False )
)
2018-08-07 07:57:59 +00:00
else :
return None
2018-07-14 08:59:17 +00:00
def get_associated_ptr_v6_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the PTR records related to the current IP type, if reverse DNS
is enabled for IPv6 .
"""
2018-07-14 08:59:17 +00:00
from re2o . utils import all_active_interfaces
2019-11-04 16:55:03 +00:00
2018-08-07 07:57:59 +00:00
if self . reverse_v6 :
2019-11-04 16:55:03 +00:00
return all_active_interfaces ( full = True ) . filter ( machine_type__ip_type = self )
2018-08-07 07:57:59 +00:00
else :
return None
2018-07-14 08:59:17 +00:00
2020-06-09 09:27:35 +00:00
def all_machine_types ( self ) :
""" Get all machine types associated with this ip type (self). """
return MachineType . objects . filter ( ip_type = self )
2017-07-21 03:06:53 +00:00
def clean ( self ) :
2020-04-29 22:17:01 +00:00
"""
Check if :
* ip_stop is after ip_start
* the range is not more than a / 16
* the range is disjoint from existing ranges
* the IPv6 prefix is formatted
"""
2020-04-21 20:30:06 +00:00
if not self . domaine_ip_start or not self . domaine_ip_stop :
raise ValidationError ( _ ( " Domaine IPv4 start and stop must be valid " ) )
2017-08-28 22:35:03 +00:00
if IPAddress ( self . domaine_ip_start ) > IPAddress ( self . domaine_ip_stop ) :
2018-08-05 16:48:22 +00:00
raise ValidationError ( _ ( " Range end must be after range start... " ) )
2020-04-29 22:17:01 +00:00
# The range should not be more than a /16
2017-08-28 22:35:03 +00:00
if self . ip_range . size > 65536 :
2019-11-04 16:55:03 +00:00
raise ValidationError (
_ (
" The range is too large, you can ' t create "
" a larger one than a /16. "
)
)
2020-04-29 22:17:01 +00:00
# Check that the ranges do not overlap
2017-08-26 13:10:18 +00:00
for element in IpType . objects . all ( ) . exclude ( pk = self . pk ) :
2017-07-21 03:06:53 +00:00
if not self . ip_set . isdisjoint ( element . ip_set ) :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2020-04-30 20:27:21 +00:00
_ ( " The specified range is not disjoint from existing " " ranges. " )
2019-11-04 16:55:03 +00:00
)
2020-04-29 22:17:01 +00:00
# Format the IPv6 prefix
2017-10-03 00:36:39 +00:00
if self . prefix_v6 :
2019-11-04 16:55:03 +00:00
self . prefix_v6 = str ( IPNetwork ( self . prefix_v6 + " /64 " ) . network )
2020-04-29 22:17:01 +00:00
# Check if the domain network/netmask contains the domain IP start-stop
2018-08-06 22:10:54 +00:00
if self . domaine_ip_network :
2019-11-04 16:55:03 +00:00
if (
not self . domaine_ip_start in self . ip_network
or not self . domaine_ip_stop in self . ip_network
) :
raise ValidationError (
_ (
" If you specify a domain network or "
" netmask, it must contain the "
" domain ' s IP range. "
)
)
2017-07-21 03:06:53 +00:00
return
def save ( self , * args , * * kwargs ) :
self . clean ( )
super ( IpType , self ) . save ( * args , * * kwargs )
2018-04-14 18:19:02 +00:00
@staticmethod
def can_use_all ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can use all IP types without restrictions.
Args :
user_request : the user requesting to use all IP types .
Returns :
A tuple indicating whether the user can use all IP types and a
message if not .
"""
2019-09-06 12:14:33 +00:00
return (
2019-11-04 16:55:03 +00:00
user_request . has_perm ( " machines.use_all_iptype " ) ,
2019-09-06 12:14:33 +00:00
None ,
2019-11-04 16:55:03 +00:00
( " machines.use_all_iptype " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-12-30 00:48:23 +00:00
2016-07-02 22:27:22 +00:00
def __str__ ( self ) :
2019-03-03 16:28:33 +00:00
return self . name
2016-07-03 01:12:41 +00:00
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Vlan ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" VLAN.
The VLAN ID is limited between 0 and 4096.
Attributes :
vlan_id : the ID of the VLAN .
name : the name of the VLAN .
comment : the comment to describe the VLAN .
arp_protect : whether ARP protection is enabled .
dhcp_snooping : whether DHCP snooping is enabled .
dhcpv6_snooping : whether DHCPv6 snooping is enabled .
igmp : whether IGMP ( v4 multicast management ) is enabled .
mld : whether MLD ( v6 multicast management ) is enabled .
"""
2019-11-04 16:55:03 +00:00
2017-10-15 18:37:21 +00:00
vlan_id = models . PositiveIntegerField ( validators = [ MaxValueValidator ( 4095 ) ] )
2017-08-26 13:10:18 +00:00
name = models . CharField ( max_length = 256 )
comment = models . CharField ( max_length = 256 , blank = True )
2020-04-29 22:17:01 +00:00
# Additional settings
2018-07-08 02:08:01 +00:00
arp_protect = models . BooleanField ( default = False )
dhcp_snooping = models . BooleanField ( default = False )
dhcpv6_snooping = models . BooleanField ( default = False )
2019-11-16 14:07:15 +00:00
igmp = models . BooleanField ( default = False , help_text = _ ( " v4 multicast management. " ) )
mld = models . BooleanField ( default = False , help_text = _ ( " v6 multicast management. " ) )
2018-07-08 18:32:47 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_vlan " , _ ( " Can view a VLAN object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " VLAN " )
verbose_name_plural = _ ( " VLANs " )
2017-12-31 18:47:22 +00:00
2017-08-26 13:10:18 +00:00
def __str__ ( self ) :
return self . name
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Nas ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" NAS device, related to a machine type.
Attributes :
name : the name of the NAS device .
nas_type : the type of the NAS device .
machine_type : the machine type of the NAS device .
port_access_mode : the access mode of the port related to the NAS
device .
autocapture_mac : whether MAC autocapture is enabled .
"""
2019-11-04 16:55:03 +00:00
default_mode = " 802.1X "
AUTH = ( ( " 802.1X " , " 802.1X " ) , ( " Mac-address " , _ ( " MAC-address " ) ) )
2017-09-13 13:04:09 +00:00
2017-09-10 22:33:45 +00:00
name = models . CharField ( max_length = 255 , unique = True )
2017-10-15 20:10:33 +00:00
nas_type = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" MachineType " , on_delete = models . PROTECT , related_name = " nas_type "
2017-10-15 20:10:33 +00:00
)
machine_type = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" MachineType " , on_delete = models . PROTECT , related_name = " machinetype_on_nas "
2017-10-15 20:10:33 +00:00
)
port_access_mode = models . CharField (
2019-11-04 16:55:03 +00:00
choices = AUTH , default = default_mode , max_length = 32
2017-10-15 20:10:33 +00:00
)
2017-09-14 13:44:51 +00:00
autocapture_mac = models . BooleanField ( default = False )
2017-09-10 22:33:45 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_nas " , _ ( " Can view a NAS device object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " NAS device " )
verbose_name_plural = _ ( " NAS devices " )
2017-12-31 18:47:22 +00:00
2017-09-10 22:33:45 +00:00
def __str__ ( self ) :
return self . name
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class SOA ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" SOA record.
Default values come from the RIPE ' s recommendations here:
2017-10-19 23:52:38 +00:00
https : / / www . ripe . net / publications / docs / ripe - 203
2020-04-29 22:17:01 +00:00
Attributes :
name : the name of the SOA record .
mail : the contact email address of the SOA record .
refresh : the number of seconds before the secondary DNS need to
refresh .
retry : the number of seconds before the secondary DNS need to retry
in case of timeout .
expire : the number of seconds before the secondary DNS stop answering
requests in case of timeout .
ttl : the Time To Live of the SOA record .
2017-10-19 23:52:38 +00:00
"""
2019-11-04 16:55:03 +00:00
2017-10-21 12:49:03 +00:00
name = models . CharField ( max_length = 255 )
2019-11-16 14:07:15 +00:00
mail = models . EmailField ( help_text = _ ( " Contact email address for the zone. " ) )
2017-10-19 23:52:38 +00:00
refresh = models . PositiveIntegerField (
2018-04-13 22:48:44 +00:00
default = 86400 , # 24 hours
2019-11-04 16:55:03 +00:00
help_text = _ (
" Seconds before the secondary DNS have to ask the primary "
2019-11-16 14:07:15 +00:00
" DNS serial to detect a modification. "
2019-11-04 16:55:03 +00:00
) ,
2017-10-19 23:52:38 +00:00
)
retry = models . PositiveIntegerField (
2018-04-13 22:48:44 +00:00
default = 7200 , # 2 hours
2019-11-04 16:55:03 +00:00
help_text = _ (
" Seconds before the secondary DNS ask the serial again in "
2019-11-16 14:07:15 +00:00
" case of a primary DNS timeout. "
2019-11-04 16:55:03 +00:00
) ,
2017-10-19 23:52:38 +00:00
)
expire = models . PositiveIntegerField (
2018-04-13 22:48:44 +00:00
default = 3600000 , # 1000 hours
2019-11-04 16:55:03 +00:00
help_text = _ (
" Seconds before the secondary DNS stop answering requests "
2019-11-16 14:07:15 +00:00
" in case of primary DNS timeout. "
2019-11-04 16:55:03 +00:00
) ,
2017-10-19 23:52:38 +00:00
)
ttl = models . PositiveIntegerField (
2019-11-16 14:07:15 +00:00
default = 172800 , help_text = _ ( " Time To Live. " ) # 2 days
2017-10-19 23:52:38 +00:00
)
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_soa " , _ ( " Can view an SOA record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " SOA record " )
verbose_name_plural = _ ( " SOA records " )
2017-12-31 18:47:22 +00:00
2017-10-19 23:52:38 +00:00
def __str__ ( self ) :
return str ( self . name )
@cached_property
def dns_soa_param ( self ) :
"""
2020-04-29 22:17:01 +00:00
Get the following fields of the SOA record :
* refresh
* retry
* expire
* ttl
2017-10-19 23:52:38 +00:00
"""
return (
2019-11-04 16:55:03 +00:00
" {refresh} ; refresh \n "
" {retry} ; retry \n "
" {expire} ; expire \n "
" {ttl} ; TTL "
2017-10-19 23:52:38 +00:00
) . format (
2017-10-20 00:28:47 +00:00
refresh = str ( self . refresh ) . ljust ( 12 ) ,
retry = str ( self . retry ) . ljust ( 12 ) ,
expire = str ( self . expire ) . ljust ( 12 ) ,
2019-11-04 16:55:03 +00:00
ttl = str ( self . ttl ) . ljust ( 12 ) ,
2017-10-19 23:52:38 +00:00
)
@cached_property
def dns_soa_mail ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the contact email address formatted in the SOA record. """
2019-11-04 16:55:03 +00:00
mail_fields = str ( self . mail ) . split ( " @ " )
return mail_fields [ 0 ] . replace ( " . " , " \\ . " ) + " . " + mail_fields [ 1 ] + " . "
2017-10-19 23:52:38 +00:00
@classmethod
def new_default_soa ( cls ) :
2020-04-29 22:17:01 +00:00
""" Create a new default SOA, useful for new extensions.
/ ! \ Never delete or rename this function , it is used to make migrations
of the database .
"""
2018-04-13 22:48:44 +00:00
return cls . objects . get_or_create (
2019-11-04 16:55:03 +00:00
name = _ ( " SOA to edit " ) , mail = " postmaster@example.com "
2018-04-13 22:48:44 +00:00
) [ 0 ] . pk
2017-10-19 23:52:38 +00:00
2018-03-31 15:18:39 +00:00
class Extension ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Extension.
DNS extension such as example . org .
Attributes :
name : the name of the extension .
need_infra : whether the ' infra ' right is required .
origin : the A record ( IpList ) related to the extension .
origin_v6 : the AAAA record related to the extension .
soa : the SOA record related to the extension .
"""
2019-11-04 16:55:03 +00:00
2017-11-16 01:33:57 +00:00
name = models . CharField (
max_length = 255 ,
unique = True ,
2019-11-16 14:07:15 +00:00
help_text = _ ( " Zone name, must begin with a dot (.example.org). " ) ,
2017-11-16 01:33:57 +00:00
)
2016-11-19 22:19:44 +00:00
need_infra = models . BooleanField ( default = False )
2018-04-09 20:49:44 +00:00
origin = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" IpList " ,
2017-10-15 20:10:33 +00:00
on_delete = models . PROTECT ,
blank = True ,
2017-11-16 01:33:57 +00:00
null = True ,
2019-11-16 14:07:15 +00:00
help_text = _ ( " A record associated with the zone. " ) ,
2017-10-15 20:10:33 +00:00
)
2017-10-18 14:27:48 +00:00
origin_v6 = models . GenericIPAddressField (
2019-11-04 16:55:03 +00:00
protocol = " IPv6 " ,
2017-10-18 14:27:48 +00:00
null = True ,
2017-11-16 01:33:57 +00:00
blank = True ,
2019-11-16 14:07:15 +00:00
help_text = _ ( " AAAA record associated with the zone. " ) ,
2017-10-19 23:52:38 +00:00
)
2019-11-04 16:55:03 +00:00
soa = models . ForeignKey ( " SOA " , on_delete = models . CASCADE )
2018-12-24 14:01:19 +00:00
dnssec = models . BooleanField (
2019-11-16 14:07:15 +00:00
default = False , help_text = _ ( " Should the zone be signed with DNSSEC. " )
2018-12-24 14:01:19 +00:00
)
2016-07-08 15:54:06 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_extension " , _ ( " Can view an extension object " ) ) ,
( " use_all_extension " , _ ( " Can use all extensions " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " DNS extension " )
verbose_name_plural = _ ( " DNS extensions " )
2017-12-31 18:47:22 +00:00
2017-09-06 09:07:36 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" A DNS A and AAAA entry on origin for the current extension. """
2017-10-18 14:27:48 +00:00
entry = " "
if self . origin :
2017-10-20 01:24:14 +00:00
entry + = " @ IN A " + str ( self . origin )
2017-10-18 14:27:48 +00:00
if self . origin_v6 :
if entry :
entry + = " \n "
2017-10-20 01:24:14 +00:00
entry + = " @ IN AAAA " + str ( self . origin_v6 )
2017-10-18 14:27:48 +00:00
return entry
2017-09-06 09:07:36 +00:00
2018-07-29 17:07:40 +00:00
def get_associated_sshfp_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all SSHFP records related to the extension. """
2018-07-29 11:46:52 +00:00
from re2o . utils import all_active_assigned_interfaces
2019-11-04 16:55:03 +00:00
return (
all_active_assigned_interfaces ( )
. filter ( machine_type__ip_type__extension = self )
. filter ( machine__id__in = SshFp . objects . values ( " machine " ) )
)
2018-07-29 11:46:52 +00:00
2018-06-10 00:47:25 +00:00
def get_associated_a_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all A records related to the extension. """
2018-06-23 21:36:01 +00:00
from re2o . utils import all_active_assigned_interfaces
2019-11-04 16:55:03 +00:00
return (
all_active_assigned_interfaces ( )
. filter ( machine_type__ip_type__extension = self )
. filter ( ipv4__isnull = False )
)
2018-06-10 00:47:25 +00:00
def get_associated_aaaa_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all AAAA records related to the extension. """
2018-06-23 21:36:01 +00:00
from re2o . utils import all_active_interfaces
2019-11-04 16:55:03 +00:00
return all_active_interfaces ( full = True ) . filter (
machine_type__ip_type__extension = self
)
2018-06-10 00:47:25 +00:00
def get_associated_cname_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all CNAME records related to the extension. """
2018-06-23 21:36:01 +00:00
from re2o . utils import all_active_assigned_interfaces
2019-11-04 16:55:03 +00:00
return (
Domain . objects . filter ( extension = self )
. filter ( cname__interface_parent__in = all_active_assigned_interfaces ( ) )
. prefetch_related ( " cname " )
)
2018-06-10 00:47:25 +00:00
2018-11-15 15:08:47 +00:00
def get_associated_dname_records ( self ) :
2020-04-29 22:17:01 +00:00
""" Get all DNAME records related to the extension. """
2019-11-04 16:55:03 +00:00
return DName . objects . filter ( alias = self )
2018-11-15 15:08:47 +00:00
2018-04-14 18:19:02 +00:00
@staticmethod
def can_use_all ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can use all extensions without restrictions.
Args :
user_request : the user requesting to use all extensions .
Returns :
A tuple indicating whether the user can use all extensions and a
message if not .
"""
2019-11-04 16:55:03 +00:00
can = user_request . has_perm ( " machines.use_all_extension " )
2019-09-06 12:14:33 +00:00
return (
2019-09-09 12:40:40 +00:00
can ,
2019-11-16 14:07:15 +00:00
_ ( " You don ' t have the right to use all extensions. " ) if not can else None ,
2019-11-04 16:55:03 +00:00
( " machines.use_all_extension " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-12-29 00:42:00 +00:00
2020-12-31 18:50:41 +00:00
@classmethod
def can_list ( cls , user_request , * _args , * * _kwargs ) :
""" All users can list unprivileged extensions
Only members of privileged groups can list all .
: param user_request : The user who wants to view the list .
: return : True if the user can view the list and an explanation
message .
"""
can , _message , _group = cls . can_use_all ( user_request )
if can :
return (
True ,
None ,
None ,
cls . objects . all ( )
)
else :
return (
2021-01-02 22:03:13 +00:00
True ,
2020-12-31 18:50:41 +00:00
_ ( " You don ' t have the right to list all extensions. " ) ,
( " machines.use_all_extension " , ) ,
cls . objects . filter ( need_infra = False ) ,
)
2016-07-08 15:54:06 +00:00
def __str__ ( self ) :
return self . name
2016-07-03 01:12:41 +00:00
2018-01-30 02:02:43 +00:00
def clean ( self , * args , * * kwargs ) :
2019-11-04 16:55:03 +00:00
if self . name and self . name [ 0 ] != " . " :
2018-08-05 16:48:22 +00:00
raise ValidationError ( _ ( " An extension must begin with a dot. " ) )
2017-11-16 01:33:57 +00:00
super ( Extension , self ) . clean ( * args , * * kwargs )
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Mx ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" MX record.
TODO link an MX record to an interface .
Attributes :
zone : the extension related to the MX record .
priority : the priority of the MX record .
name : the domain related to the MX record .
ttl : the Time To Live of the MX record .
"""
2019-11-04 16:55:03 +00:00
zone = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2018-08-07 09:19:45 +00:00
priority = models . PositiveIntegerField ( )
2019-11-04 16:55:03 +00:00
name = models . ForeignKey ( " Domain " , on_delete = models . PROTECT )
2019-10-02 20:48:33 +00:00
ttl = models . PositiveIntegerField (
2019-11-04 16:55:03 +00:00
verbose_name = _ ( " Time To Live (TTL) " ) , default = 172800 # 2 days
2019-10-02 20:48:33 +00:00
)
2016-11-19 16:44:43 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_mx " , _ ( " Can view an MX record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " MX record " )
verbose_name_plural = _ ( " MX records " )
2017-12-31 18:47:22 +00:00
2017-09-06 09:07:36 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete DNS entry of the MX record, to put in zone files.
"""
2018-04-13 22:48:44 +00:00
return " @ IN MX {prior} {name} " . format (
2019-11-04 16:55:03 +00:00
prior = str ( self . priority ) . ljust ( 3 ) , name = str ( self . name )
2018-04-13 22:48:44 +00:00
)
2017-09-06 09:07:36 +00:00
2016-11-19 16:44:43 +00:00
def __str__ ( self ) :
2019-11-04 16:55:03 +00:00
return str ( self . zone ) + " " + str ( self . priority ) + " " + str ( self . name )
2016-11-19 16:44:43 +00:00
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Ns ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" NS record.
Attributes :
zone : the extension related to the NS record .
ns : the domain related to the NS record .
ttl : the Time To Live of the NS record .
"""
2019-11-04 16:55:03 +00:00
zone = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
ns = models . ForeignKey ( " Domain " , on_delete = models . PROTECT )
2019-10-02 20:48:33 +00:00
ttl = models . PositiveIntegerField (
2019-11-04 16:55:03 +00:00
verbose_name = _ ( " Time To Live (TTL) " ) , default = 172800 # 2 days
2019-10-02 20:48:33 +00:00
)
2016-11-19 16:44:43 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_ns " , _ ( " Can view an NS record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " NS record " )
verbose_name_plural = _ ( " NS records " )
2017-12-31 18:47:22 +00:00
2017-09-06 09:07:36 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete DNS entry of the NS record, to put in zone files.
"""
2017-10-22 03:04:49 +00:00
return " @ IN NS " + str ( self . ns )
2017-09-06 09:07:36 +00:00
2016-11-19 17:21:05 +00:00
def __str__ ( self ) :
2019-11-04 16:55:03 +00:00
return str ( self . zone ) + " " + str ( self . ns )
2016-11-19 17:21:05 +00:00
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Txt ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" TXT record.
Attributes :
zone : the extension related to the TXT record .
field1 : the first field of the TXT record .
field2 : the second field of the TXT record .
ttl : the Time To Live of the TXT record .
"""
2019-11-04 16:55:03 +00:00
zone = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2017-09-05 16:18:41 +00:00
field1 = models . CharField ( max_length = 255 )
2017-11-15 02:06:33 +00:00
field2 = models . TextField ( max_length = 2047 )
2019-10-02 20:48:33 +00:00
ttl = models . PositiveIntegerField (
2019-11-04 16:55:03 +00:00
verbose_name = _ ( " Time To Live (TTL) " ) , default = 172800 # 2 days
2019-10-02 20:48:33 +00:00
)
2017-10-15 20:10:33 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_txt " , _ ( " Can view a TXT record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " TXT record " )
verbose_name_plural = _ ( " TXT records " )
2017-12-31 18:47:22 +00:00
2017-09-05 16:18:41 +00:00
def __str__ ( self ) :
2019-11-04 16:55:03 +00:00
return str ( self . zone ) + " : " + str ( self . field1 ) + " " + str ( self . field2 )
2017-09-05 16:18:41 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete DNS entry of the TXT record, to put in zone files.
"""
2017-10-20 01:24:14 +00:00
return str ( self . field1 ) . ljust ( 15 ) + " IN TXT " + str ( self . field2 )
2017-09-05 16:18:41 +00:00
2017-10-15 20:10:33 +00:00
2018-06-25 14:50:45 +00:00
class DName ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" DNAME record.
Attributes :
zone : the extension related to the DNAME record .
alias : the alias of the DNAME record .
ttl : the Time To Live of the DNAME record .
"""
2019-11-04 16:55:03 +00:00
zone = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2018-06-25 14:50:45 +00:00
alias = models . CharField ( max_length = 255 )
2019-10-02 21:53:27 +00:00
ttl = models . PositiveIntegerField (
2019-11-04 16:55:03 +00:00
verbose_name = _ ( " Time To Live (TTL) " ) , default = 172800 # 2 days
2019-10-02 21:53:27 +00:00
)
2018-06-25 14:50:45 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_dname " , _ ( " Can view a DNAME record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " DNAME record " )
verbose_name_plural = _ ( " DNAME records " )
2018-06-25 14:50:45 +00:00
def __str__ ( self ) :
return str ( self . zone ) + " : " + str ( self . alias )
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete DNS entry of the TXT record, to put in zone files.
"""
2018-07-29 14:45:12 +00:00
return str ( self . alias ) . ljust ( 15 ) + " IN DNAME " + str ( self . zone )
2018-06-25 14:50:45 +00:00
2018-03-31 15:18:39 +00:00
class Srv ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" SRV record.
Attributes :
service : the name of the service of the SRV record .
protocole : the protocol of the service of the SRV record .
extension : the extension of the SRV record .
ttl : the Time To Live of the SRV record .
priority : the priority of the target server .
weight : the relative weight for records with the same priority .
port : the TCP / UDP port of the SRV record .
target : the target server of the SRV record .
"""
2019-11-04 16:55:03 +00:00
TCP = " TCP "
UDP = " UDP "
2017-11-16 01:33:57 +00:00
2018-04-13 22:48:44 +00:00
service = models . CharField ( max_length = 31 )
2017-11-16 01:33:57 +00:00
protocole = models . CharField (
2019-11-04 16:55:03 +00:00
max_length = 3 , choices = ( ( TCP , " TCP " ) , ( UDP , " UDP " ) ) , default = TCP
2017-11-16 01:33:57 +00:00
)
2019-11-04 16:55:03 +00:00
extension = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2017-11-16 01:33:57 +00:00
ttl = models . PositiveIntegerField (
2019-11-16 14:07:15 +00:00
default = 172800 , help_text = _ ( " Time To Live. " ) # 2 days
2017-11-16 01:33:57 +00:00
)
priority = models . PositiveIntegerField (
2017-11-16 01:53:05 +00:00
default = 0 ,
2017-11-16 01:33:57 +00:00
validators = [ MaxValueValidator ( 65535 ) ] ,
2019-11-04 16:55:03 +00:00
help_text = _ (
" Priority of the target server (positive integer value, "
" the lower it is, the more the server will be used if "
2019-11-16 14:07:15 +00:00
" available). "
2019-11-04 16:55:03 +00:00
) ,
2017-11-16 01:33:57 +00:00
)
weight = models . PositiveIntegerField (
2017-11-16 01:53:05 +00:00
default = 0 ,
2017-11-16 01:33:57 +00:00
validators = [ MaxValueValidator ( 65535 ) ] ,
2019-11-04 16:55:03 +00:00
help_text = _ (
" Relative weight for records with the same priority "
2019-11-16 14:07:15 +00:00
" (integer value between 0 and 65535). "
2019-11-04 16:55:03 +00:00
) ,
2017-11-16 01:33:57 +00:00
)
port = models . PositiveIntegerField (
2019-11-16 14:07:15 +00:00
validators = [ MaxValueValidator ( 65535 ) ] , help_text = _ ( " TCP/UDP port. " )
2017-11-16 01:33:57 +00:00
)
target = models . ForeignKey (
2019-11-16 14:07:15 +00:00
" Domain " , on_delete = models . PROTECT , help_text = _ ( " Target server. " )
2017-11-16 01:33:57 +00:00
)
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_srv " , _ ( " Can view an SRV record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " SRV record " )
verbose_name_plural = _ ( " SRV records " )
2017-12-31 18:47:22 +00:00
2017-11-16 01:33:57 +00:00
def __str__ ( self ) :
2019-11-04 16:55:03 +00:00
return (
str ( self . service )
+ " "
+ str ( self . protocole )
+ " "
+ str ( self . extension )
+ " "
+ str ( self . priority )
+ " "
+ str ( self . weight )
+ str ( self . port )
+ str ( self . target )
)
2017-11-16 01:33:57 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the complete DNS entry of the SRV record, to put in zone files.
"""
2019-11-04 16:55:03 +00:00
return (
str ( self . service )
+ " ._ "
+ str ( self . protocole ) . lower ( )
+ str ( self . extension )
+ " . "
+ str ( self . ttl )
+ " IN SRV "
+ str ( self . priority )
+ " "
+ str ( self . weight )
+ " "
+ str ( self . port )
+ " "
+ str ( self . target )
+ " . "
)
2017-11-16 01:33:57 +00:00
2018-07-29 17:07:40 +00:00
class SshFp ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" SSH public key fingerprint.
Attributes :
machine : the machine related to the SSH fingerprint .
pub_key_entry : the SSH public key related to the SSH fingerprint .
algo : the algorithm used for the SSH fingerprint .
comment : the comment to describe the SSH fingerprint .
"""
2018-07-29 17:07:40 +00:00
ALGO = (
( " ssh-rsa " , " ssh-rsa " ) ,
( " ssh-ed25519 " , " ssh-ed25519 " ) ,
( " ecdsa-sha2-nistp256 " , " ecdsa-sha2-nistp256 " ) ,
( " ecdsa-sha2-nistp384 " , " ecdsa-sha2-nistp384 " ) ,
( " ecdsa-sha2-nistp521 " , " ecdsa-sha2-nistp521 " ) ,
)
2019-11-04 16:55:03 +00:00
machine = models . ForeignKey ( " Machine " , on_delete = models . CASCADE )
2019-11-16 14:07:15 +00:00
pub_key_entry = models . TextField ( help_text = _ ( " SSH public key. " ) , max_length = 2048 )
2019-11-04 16:55:03 +00:00
algo = models . CharField ( choices = ALGO , max_length = 32 )
2018-07-29 17:07:40 +00:00
comment = models . CharField (
2019-11-16 14:07:15 +00:00
help_text = _ ( " Comment. " ) , max_length = 255 , null = True , blank = True
2018-07-29 17:07:40 +00:00
)
@cached_property
def algo_id ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the ID of the algorithm for this key. """
2018-07-29 17:07:40 +00:00
if " ecdsa " in self . algo :
return 3
elif " rsa " in self . algo :
return 1
else :
return 2
@cached_property
def hash ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the hashes for the pub key with correct ID.
See RFC : 1 is sha1 , 2 is sha256 .
"""
2021-01-08 23:47:04 +00:00
pubkey = self . base64_pubkey ( )
2018-07-29 17:07:40 +00:00
return {
2021-01-08 22:46:25 +00:00
" 1 " : hashlib . sha1 ( pubkey ) . hexdigest ( ) ,
" 2 " : hashlib . sha256 ( pubkey ) . hexdigest ( ) ,
2018-07-29 17:07:40 +00:00
}
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_sshfp " , _ ( " Can view an SSHFP record object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " SSHFP record " )
verbose_name_plural = _ ( " SSHFP records " )
2018-07-29 17:07:40 +00:00
def can_view ( self , user_request , * _args , * * _kwargs ) :
return self . machine . can_view ( user_request , * _args , * * _kwargs )
def can_edit ( self , user_request , * args , * * kwargs ) :
return self . machine . can_edit ( user_request , * args , * * kwargs )
def can_delete ( self , user_request , * args , * * kwargs ) :
return self . machine . can_delete ( user_request , * args , * * kwargs )
2021-01-08 23:47:04 +00:00
def base64_pubkey ( self ) :
""" Function to decode in base64 the pub key entry
Returns :
Base64 decoded value of pub_key_entry
Because of b64 MUST be divided by 4 , we add a " padding " = carracter 3 times .
This padding is then ignored if the pubkey is greater than a multiple of 4.
More informations on : https : / / gist . github . com / perrygeo / ee7c65bb1541ff6ac770
As said in the thread , this fix is not optimal , however it is very simple as
no options on b64decode function exists . """
return base64 . b64decode ( self . pub_key_entry + " === " )
def clean ( self , * args , * * kwargs ) :
""" Check if the pub_key_entry is a valid base64 entry.
Raises :
ValidationError : the pub key entry is not a valid base64 enty .
"""
try :
self . base64_pubkey ( )
except ValueError :
raise ValidationError ( _ ( " Ssh pub key entry is incorrect base64 entry " ) )
super ( SshFp , self ) . clean ( * args , * * kwargs )
2018-07-29 17:07:40 +00:00
def __str__ ( self ) :
2019-11-04 16:55:03 +00:00
return str ( self . algo ) + " " + str ( self . comment )
2018-07-29 17:07:40 +00:00
2018-04-13 22:48:44 +00:00
class Interface ( RevMixin , AclMixin , FieldPermissionModelMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Interface, the key object of the app machines.
Attributes :
ipv4 : the IPv4 address ( IpList ) of the interface .
mac_address : the MAC address of the interface .
machine : the machine to which the interface belongs .
machine_type : the machine type of the interface .
details : the details to describe the interface .
port_lists : the ports opening list of the interface .
"""
2019-11-04 16:55:03 +00:00
2017-10-15 20:10:33 +00:00
ipv4 = models . OneToOneField (
2019-11-04 16:55:03 +00:00
" IpList " , on_delete = models . PROTECT , blank = True , null = True
2017-10-15 20:10:33 +00:00
)
2018-06-22 15:48:10 +00:00
mac_address = MACAddressField ( integer = False )
2019-11-04 16:55:03 +00:00
machine = models . ForeignKey ( " Machine " , on_delete = models . CASCADE )
machine_type = models . ForeignKey ( " MachineType " , on_delete = models . PROTECT )
2016-07-04 00:48:24 +00:00
details = models . CharField ( max_length = 255 , blank = True )
2019-11-04 16:55:03 +00:00
port_lists = models . ManyToManyField ( " OuverturePortList " , blank = True )
2016-07-03 01:12:41 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_interface " , _ ( " Can view an interface object " ) ) ,
2019-11-04 16:55:03 +00:00
( " change_interface_machine " , _ ( " Can change the owner of an interface " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " interface " )
verbose_name_plural = _ ( " interfaces " )
2017-12-31 18:47:22 +00:00
2017-05-26 22:43:51 +00:00
@cached_property
2016-07-18 21:22:59 +00:00
def is_active ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the state of the interface.
The interface is active if the related machine is active and the owner
has access .
"""
2016-07-18 21:22:59 +00:00
machine = self . machine
user = self . machine . user
2017-07-18 01:49:36 +00:00
return machine . active and user . has_access ( )
2016-07-18 21:22:59 +00:00
2017-10-03 00:36:39 +00:00
@cached_property
2018-01-29 02:53:49 +00:00
def ipv6_slaac ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the IPv6 type object from the prefix related to the parent IP
type .
"""
2019-03-03 16:28:33 +00:00
if self . machine_type . ip_type . prefix_v6 :
2017-10-15 20:10:33 +00:00
return EUI ( self . mac_address ) . ipv6 (
2019-03-03 16:28:33 +00:00
IPNetwork ( self . machine_type . ip_type . prefix_v6 ) . network
2017-10-15 20:10:33 +00:00
)
2017-10-03 00:36:39 +00:00
else :
return None
2018-01-30 05:33:56 +00:00
@cached_property
def gen_ipv6_dhcpv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Create an IPv6 address to assign with DHCPv6. """
2019-11-04 16:55:03 +00:00
prefix_v6 = self . machine_type . ip_type . prefix_v6 . encode ( ) . decode ( " utf-8 " )
2018-01-30 05:33:56 +00:00
if not prefix_v6 :
return None
2018-04-13 22:48:44 +00:00
return IPv6Address (
2019-11-04 16:55:03 +00:00
IPv6Address ( prefix_v6 ) . exploded [ : 20 ] + IPv6Address ( self . id ) . exploded [ 20 : ]
2018-04-13 22:48:44 +00:00
)
2019-11-04 16:55:03 +00:00
2019-01-27 09:39:18 +00:00
@cached_property
def get_vendor ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the vendor from the MAC address of the interface. """
2019-01-27 09:39:18 +00:00
mac = EUI ( self . mac_address )
try :
2019-11-04 16:55:03 +00:00
oui = mac . oui
vendor = oui . registration ( ) . org
2020-01-24 19:59:36 +00:00
except ( IndexError , NotRegisteredError ) as error :
2019-11-16 14:07:15 +00:00
vendor = _ ( " Unknown vendor. " )
2019-11-04 16:55:03 +00:00
return vendor
2018-01-30 05:33:56 +00:00
def sync_ipv6_dhcpv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Assign an IPv6 address by DHCPv6, computed from the interface ' s ID.
"""
2018-01-30 05:33:56 +00:00
ipv6_dhcpv6 = self . gen_ipv6_dhcpv6
if not ipv6_dhcpv6 :
return
ipv6 = Ipv6List . objects . filter ( ipv6 = str ( ipv6_dhcpv6 ) ) . first ( )
if not ipv6 :
ipv6 = Ipv6List ( ipv6 = str ( ipv6_dhcpv6 ) )
ipv6 . interface = self
ipv6 . save ( )
return
2018-01-29 02:53:49 +00:00
def sync_ipv6_slaac ( self ) :
2020-04-29 22:17:01 +00:00
""" Create, update and delete if necessary the IPv6 SLAAC related to the
interface .
"""
2018-01-29 02:53:49 +00:00
ipv6_slaac = self . ipv6_slaac
if not ipv6_slaac :
return
2019-11-04 16:55:03 +00:00
ipv6_object = Ipv6List . objects . filter ( interface = self , slaac_ip = True ) . first ( )
2018-01-29 02:53:49 +00:00
if not ipv6_object :
ipv6_object = Ipv6List ( interface = self , slaac_ip = True )
if ipv6_object . ipv6 != str ( ipv6_slaac ) :
ipv6_object . ipv6 = str ( ipv6_slaac )
ipv6_object . save ( )
2018-01-30 05:33:56 +00:00
def sync_ipv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Create and update the IPv6 addresses according to the IPv6 mode set.
"""
2019-11-04 16:55:03 +00:00
if preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " SLAAC " :
2018-01-30 05:33:56 +00:00
self . sync_ipv6_slaac ( )
2019-11-04 16:55:03 +00:00
elif (
preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " DHCPV6 "
) :
2018-01-30 05:33:56 +00:00
self . sync_ipv6_dhcpv6 ( )
else :
return
2017-10-03 00:36:39 +00:00
def ipv6 ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the queryset of the IPv6 addresses list.
The IPv6 SLAAC is returned only if SLAAC mode is enabled ( and not
DHCPv6 ) .
"""
2019-11-04 16:55:03 +00:00
if preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " SLAAC " :
2020-08-04 22:06:05 +00:00
return self . ipv6list . filter ( active = True )
2019-11-04 16:55:03 +00:00
elif (
preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " DHCPV6 "
) :
2020-08-04 22:06:05 +00:00
return self . ipv6list . filter ( active = True ) . filter ( slaac_ip = False )
2018-01-30 06:36:22 +00:00
else :
2018-12-23 17:48:25 +00:00
return [ ]
2017-10-03 00:36:39 +00:00
2016-11-20 16:57:10 +00:00
def mac_bare ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the mac_bare formatted MAC address. """
2016-11-20 16:57:10 +00:00
return str ( EUI ( self . mac_address , dialect = mac_bare ) ) . lower ( )
2017-09-08 14:02:11 +00:00
def filter_macaddress ( self ) :
2020-04-29 22:17:01 +00:00
""" Format the MAC address as mac_bare.
Raises :
ValidationError : the MAC address cannot be formatted as mac_bare .
"""
2017-09-19 20:09:12 +00:00
try :
2018-11-03 18:24:46 +00:00
self . mac_address = str ( EUI ( self . mac_address , dialect = default_dialect ( ) ) )
2017-10-15 20:10:33 +00:00
except :
2018-08-05 16:48:22 +00:00
raise ValidationError ( _ ( " The given MAC address is invalid. " ) )
2017-09-08 14:02:11 +00:00
2017-07-21 04:49:39 +00:00
def assign_ipv4 ( self ) :
2020-04-29 22:17:01 +00:00
""" Assign an IPv4 address to the interface. """
2019-03-03 16:28:33 +00:00
free_ips = self . machine_type . ip_type . free_ip ( )
2017-07-21 04:49:39 +00:00
if free_ips :
self . ipv4 = free_ips [ 0 ]
else :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2019-11-16 14:07:15 +00:00
_ ( " There are no IP addresses available in the slash. " )
2019-11-04 16:55:03 +00:00
)
2017-07-21 04:49:39 +00:00
return
def unassign_ipv4 ( self ) :
2020-04-29 22:17:01 +00:00
""" Unassign the IPv4 address of the interface. """
2017-07-21 04:49:39 +00:00
self . ipv4 = None
2016-11-12 08:09:28 +00:00
2019-03-17 03:46:55 +00:00
@classmethod
def mass_unassign_ipv4 ( cls , interface_list ) :
2020-04-29 22:17:01 +00:00
""" Unassign IPv4 addresses to multiple interfaces.
Args :
interface_list : the list of interfaces to be updated .
"""
2019-03-17 03:46:55 +00:00
with transaction . atomic ( ) , reversion . create_revision ( ) :
interface_list . update ( ipv4 = None )
2019-11-16 14:07:15 +00:00
reversion . set_comment ( " IPv4 unassignment " )
2019-03-17 03:46:55 +00:00
@classmethod
def mass_assign_ipv4 ( cls , interface_list ) :
2020-04-29 22:17:01 +00:00
""" Assign IPv4 addresses to multiple interfaces.
Args :
interface_list : the list of interfaces to be updated .
"""
2019-03-17 03:46:55 +00:00
for interface in interface_list :
with transaction . atomic ( ) , reversion . create_revision ( ) :
interface . assign_ipv4 ( )
interface . save ( )
2019-11-16 14:07:15 +00:00
reversion . set_comment ( " IPv4 assignment " )
2019-03-17 03:46:55 +00:00
2020-06-09 09:27:35 +00:00
def all_domains ( self ) :
""" Get all domains associated with this interface (self). """
return Domain . objects . filter ( interface_parent = self )
2017-07-23 03:03:56 +00:00
def update_type ( self ) :
2020-04-29 22:17:01 +00:00
""" Reassign addresses when the IP type of the machine type changed. """
2017-07-23 03:03:56 +00:00
self . clean ( )
self . save ( )
2019-01-22 22:41:06 +00:00
def has_private_ip ( self ) :
2020-04-29 22:17:01 +00:00
""" Check if the IPv4 address assigned is private. """
2019-01-22 22:41:06 +00:00
if self . ipv4 :
return IPAddress ( str ( self . ipv4 ) ) . is_private ( )
else :
return False
def may_have_port_open ( self ) :
2020-04-29 22:17:01 +00:00
""" Check if the interface has a public IP address. """
2019-01-22 22:41:06 +00:00
return self . ipv4 and not self . has_private_ip ( )
def clean ( self , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Format the MAC address as mac_bare (see filter_mac) and assign an
IPv4 address in the appropriate range if the current address is
nonexistent or inconsistent .
If type was an invalid value , django won ' t create an attribute type
but try clean ( ) as we may be able to create it from another value so
even if the error as yet been detected at this point , django continues
because the error might not prevent us from creating the instance . But
in our case , it ' s impossible to create a type value so we raise the
error .
"""
2019-11-04 16:55:03 +00:00
if not hasattr ( self , " machine_type " ) :
2019-01-22 22:41:06 +00:00
raise ValidationError ( _ ( " The selected IP type is invalid. " ) )
self . filter_macaddress ( )
2019-03-03 16:28:33 +00:00
if not self . ipv4 or self . machine_type . ip_type != self . ipv4 . ip_type :
2019-01-22 22:41:06 +00:00
self . assign_ipv4 ( )
super ( Interface , self ) . clean ( * args , * * kwargs )
def validate_unique ( self , * args , * * kwargs ) :
super ( Interface , self ) . validate_unique ( * args , * * kwargs )
2019-11-04 16:55:03 +00:00
interfaces_similar = Interface . objects . filter (
mac_address = self . mac_address ,
machine_type__ip_type = self . machine_type . ip_type ,
)
2019-01-22 22:41:06 +00:00
if interfaces_similar and interfaces_similar . first ( ) != self :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2019-11-16 14:07:15 +00:00
_ ( " MAC address already registered in this machine type/subnet. " )
2019-11-04 16:55:03 +00:00
)
2019-01-22 22:41:06 +00:00
2017-07-23 02:22:22 +00:00
def save ( self , * args , * * kwargs ) :
2017-09-08 14:02:11 +00:00
self . filter_macaddress ( )
2020-04-29 22:17:01 +00:00
# Check the consistency by forcing the extension
2017-10-19 05:08:10 +00:00
if self . ipv4 :
2019-03-03 16:28:33 +00:00
if self . machine_type . ip_type != self . ipv4 . ip_type :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2019-11-16 14:07:15 +00:00
_ ( " The IPv4 address and the machine type don ' t match. " )
2019-11-04 16:55:03 +00:00
)
2019-01-22 22:41:06 +00:00
self . validate_unique ( )
2017-07-23 02:22:22 +00:00
super ( Interface , self ) . save ( * args , * * kwargs )
2018-04-14 18:19:02 +00:00
@staticmethod
def can_create ( user_request , machineid , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can create an interface, or that the machine is
owned by the user .
Args :
user_request : the user requesting to create the interface .
machineid : the ID of the machine related to the interface .
Returns :
A tuple indicating whether the user can create the interface and a
message if not .
"""
2017-11-29 00:53:32 +00:00
try :
2017-11-30 20:38:16 +00:00
machine = Machine . objects . get ( pk = machineid )
2017-11-29 00:53:32 +00:00
except Machine . DoesNotExist :
2019-09-06 12:14:33 +00:00
return False , _ ( " Nonexistent machine. " ) , None
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.add_interface " ) :
if not (
preferences . models . OptionalMachine . get_cached_value ( " create_machine " )
) :
2020-04-30 20:27:21 +00:00
return (
False ,
_ ( " You don ' t have the right to add a machine. " ) ,
( " machines.add_interface " , ) ,
)
2019-11-04 16:55:03 +00:00
max_lambdauser_interfaces = preferences . models . OptionalMachine . get_cached_value (
" max_lambdauser_interfaces "
)
2017-11-29 00:53:32 +00:00
if machine . user != user_request :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You don ' t have the right to add an interface "
" to a machine of another user. "
) ,
( " machines.add_interface " , ) ,
2019-09-06 12:14:33 +00:00
)
2019-11-04 16:55:03 +00:00
if machine . user . user_interfaces ( ) . count ( ) > = max_lambdauser_interfaces :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You reached the maximum number of interfaces "
" that you are allowed to create yourself "
" ( %s ). " % max_lambdauser_interfaces
) ,
( " machines.add_interface " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-11-29 00:53:32 +00:00
2018-01-08 22:57:19 +00:00
@staticmethod
2018-04-14 18:19:02 +00:00
def can_change_machine ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can edit the machine.
Args :
user_request : the user requesting to edit the machine .
Returns :
A tuple indicating whether the user can edit the machine and a
message if not .
"""
2019-11-04 16:55:03 +00:00
can = user_request . has_perm ( " machines.change_interface_machine " )
2019-09-06 12:14:33 +00:00
return (
2019-09-09 12:40:40 +00:00
can ,
2019-11-16 14:07:15 +00:00
_ ( " You don ' t have the right to edit the machine. " ) if not can else None ,
2019-11-04 16:55:03 +00:00
( " machines.change_interface_machine " , ) ,
2019-09-06 12:14:33 +00:00
)
2018-01-08 22:57:19 +00:00
2017-11-30 20:48:32 +00:00
def can_edit ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can edit the current interface (self), or that it
is owned by the user .
Args :
user_request : the user requesting to edit self .
Returns :
A tuple indicating whether the user can edit self and a
message if not .
"""
2018-01-08 00:21:24 +00:00
if self . machine . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . machine . user . can_edit (
2019-11-04 16:55:03 +00:00
user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2019-11-04 16:55:03 +00:00
if not ( user_request . has_perm ( " machines.change_interface " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:27:21 +00:00
_ ( " You don ' t have the right to edit a machine of another " " user. " ) ,
2020-04-30 20:32:17 +00:00
( " machines.change_interface " , ) + ( permissions or ( ) ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-11-29 23:45:53 +00:00
2017-12-09 01:15:11 +00:00
def can_delete ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can delete the current interface (self), or that
it is owned by the user .
Args :
user_request : the user requesting to delete self .
Returns :
A tuple indicating whether the user can delete self and a
message if not .
"""
2018-01-08 00:21:24 +00:00
if self . machine . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . machine . user . can_edit (
2019-11-04 16:55:03 +00:00
user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2020-04-30 20:21:12 +00:00
if not ( user_request . has_perm ( " machines.delete_interface " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:36:41 +00:00
_ (
" You don ' t have the right to delete interfaces of another "
" user. "
) ,
( " machines.delete_interface " , ) + ( permissions or ( ) ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 15:32:43 +00:00
2018-04-14 18:19:02 +00:00
def can_view ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can view the current interface (self), or that it
is owned by the user .
Args :
user_request : the user requesting to view self .
Returns :
A tuple indicating whether the user can view self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.view_interface " )
and self . machine . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:21:12 +00:00
_ ( " You don ' t have the right to view interfaces other than yours. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.view_interface " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 16:43:07 +00:00
2018-01-08 22:57:19 +00:00
def __init__ ( self , * args , * * kwargs ) :
super ( Interface , self ) . __init__ ( * args , * * kwargs )
2019-11-04 16:55:03 +00:00
self . field_permissions = { " machine " : self . can_change_machine }
2018-01-08 22:57:19 +00:00
2016-07-03 14:49:29 +00:00
def __str__ ( self ) :
2016-12-24 19:04:53 +00:00
try :
domain = self . domain
except :
domain = None
return str ( domain )
2016-07-03 14:49:29 +00:00
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Ipv6List ( RevMixin , AclMixin , FieldPermissionModelMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" IPv6 addresses list.
Args :
ipv6 : the IPv6 address of the list .
interface : the interface related to the list .
slaac_ip : whether SLAAC mode is enabled .
2020-08-04 20:45:57 +00:00
active : whether the ip is to be used .
2020-04-29 22:17:01 +00:00
"""
2018-01-29 02:53:49 +00:00
2019-11-04 16:55:03 +00:00
ipv6 = models . GenericIPAddressField ( protocol = " IPv6 " )
2018-04-13 22:48:44 +00:00
interface = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" Interface " , on_delete = models . CASCADE , related_name = " ipv6list "
2018-04-13 22:48:44 +00:00
)
2018-01-29 02:53:49 +00:00
slaac_ip = models . BooleanField ( default = False )
2020-08-04 20:45:57 +00:00
active = models . BooleanField (
default = True ,
help_text = _ ( " If false,the DNS will not provide this ip. " )
)
2018-01-29 02:53:49 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_ipv6list " , _ ( " Can view an IPv6 addresses list object " ) ) ,
2019-11-04 16:55:03 +00:00
(
" change_ipv6list_slaac_ip " ,
2019-11-16 14:07:15 +00:00
_ ( " Can change the SLAAC value of an IPv6 addresses list " ) ,
2019-11-04 16:55:03 +00:00
) ,
2018-01-29 02:53:49 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " IPv6 addresses list " )
verbose_name_plural = _ ( " IPv6 addresses lists " )
2018-01-29 02:53:49 +00:00
2018-04-14 18:19:02 +00:00
@staticmethod
def can_create ( user_request , interfaceid , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can create an IPv6 address for the given
interface , or that it is owned by the user .
Args :
user_request : the user requesting to create an IPv6 address .
interfaceid : the ID of the interface to be edited .
Returns :
A tuple indicating whether the user can create an IPv6 address for
the given interface and a message if not .
"""
2018-01-29 02:53:49 +00:00
try :
interface = Interface . objects . get ( pk = interfaceid )
except Interface . DoesNotExist :
2019-09-06 12:14:33 +00:00
return False , _ ( " Nonexistent interface. " ) , None
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.add_ipv6list " ) :
2018-01-29 02:53:49 +00:00
if interface . machine . user != user_request :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
2020-04-30 20:21:12 +00:00
" You don ' t have the right to add ipv6 to a "
2019-11-04 16:55:03 +00:00
" machine of another user. "
) ,
( " machines.add_ipv6list " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2018-01-29 02:53:49 +00:00
@staticmethod
2018-04-14 18:19:02 +00:00
def can_change_slaac_ip ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if a user can change the SLAAC value. """
2019-11-04 16:55:03 +00:00
can = user_request . has_perm ( " machines.change_ipv6list_slaac_ip " )
2019-09-06 12:14:33 +00:00
return (
2019-09-09 12:40:40 +00:00
can ,
2019-11-16 14:07:15 +00:00
_ ( " You don ' t have the right to change the SLAAC value of an IPv6 address. " )
2019-11-04 16:55:03 +00:00
if not can
else None ,
( " machines.change_ipv6list_slaac_ip " , ) ,
2019-09-06 12:14:33 +00:00
)
2018-01-29 02:53:49 +00:00
def can_edit ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can edit the current IPv6 addresses list (self),
or that the related interface is owned by the user .
Args :
user_request : the user requesting to edit self .
Returns :
A tuple indicating whether the user can edit self and a
message if not .
"""
2018-01-29 02:53:49 +00:00
if self . interface . machine . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . interface . machine . user . can_edit (
2019-11-04 16:55:03 +00:00
user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2019-11-04 16:55:03 +00:00
if not ( user_request . has_perm ( " machines.change_ipv6list " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:36:41 +00:00
_ (
" You don ' t have the right to edit ipv6 of a machine of another user. "
) ,
2019-11-04 16:55:03 +00:00
( " machines.change_ipv6list " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2018-01-29 02:53:49 +00:00
def can_delete ( self , user_request , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can delete the current IPv6 addresses list (self),
or that the related interface is owned by the user .
Args :
user_request : the user requesting to delete self .
Returns :
A tuple indicating whether the user can delete self and a
message if not .
"""
2018-01-29 02:53:49 +00:00
if self . interface . machine . user != user_request :
2019-09-17 00:08:21 +00:00
can_user , _message , permissions = self . interface . machine . user . can_edit (
2019-11-04 16:55:03 +00:00
user_request , * args , * * kwargs
2019-09-06 12:14:33 +00:00
)
2020-04-30 20:21:12 +00:00
if not ( user_request . has_perm ( " machines.delete_ipv6list " ) and can_user ) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:36:41 +00:00
_ (
" You don ' t have the right to delete ipv6 of a machine of another user. "
) ,
( " machines.delete_ipv6list " , ) + ( permissions or ( ) ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2018-01-29 02:53:49 +00:00
2018-04-14 18:19:02 +00:00
def can_view ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can view the current IPv6 addresses list (self),
or that the related interface is owned by the user .
Args :
user_request : the user requesting to view self .
Returns :
A tuple indicating whether the user can view self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.view_ipv6list " )
and self . interface . machine . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:36:41 +00:00
_ (
" You don ' t have the right to view ipv6 of machines other than yours. "
) ,
2019-11-04 16:55:03 +00:00
( " machines.view_ipv6list " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2018-01-29 02:53:49 +00:00
def __init__ ( self , * args , * * kwargs ) :
super ( Ipv6List , self ) . __init__ ( * args , * * kwargs )
2019-11-04 16:55:03 +00:00
self . field_permissions = { " slaac_ip " : self . can_change_slaac_ip }
2018-01-29 02:53:49 +00:00
2018-01-30 03:51:15 +00:00
def check_and_replace_prefix ( self , prefix = None ) :
2020-04-29 22:17:01 +00:00
""" Check if the IPv6 prefix is correct and update it if not. """
2019-11-04 16:55:03 +00:00
prefix_v6 = prefix or self . interface . machine_type . ip_type . prefix_v6 . encode ( ) . decode (
" utf-8 "
)
2018-01-30 05:33:56 +00:00
if not prefix_v6 :
return
2019-11-04 16:55:03 +00:00
if (
IPv6Address ( self . ipv6 . encode ( ) . decode ( " utf-8 " ) ) . exploded [ : 20 ]
!= IPv6Address ( prefix_v6 ) . exploded [ : 20 ]
) :
2018-04-13 22:48:44 +00:00
self . ipv6 = IPv6Address (
2019-11-04 16:55:03 +00:00
IPv6Address ( prefix_v6 ) . exploded [ : 20 ]
+ IPv6Address ( self . ipv6 . encode ( ) . decode ( " utf-8 " ) ) . exploded [ 20 : ]
2018-04-13 22:48:44 +00:00
)
2018-01-30 03:51:15 +00:00
self . save ( )
2018-01-30 02:01:06 +00:00
def clean ( self , * args , * * kwargs ) :
2019-11-04 16:55:03 +00:00
if self . slaac_ip and (
Ipv6List . objects . filter ( interface = self . interface , slaac_ip = True ) . exclude (
id = self . id
)
) :
2018-08-05 16:48:22 +00:00
raise ValidationError ( _ ( " A SLAAC IP address is already registered. " ) )
2019-01-01 15:11:02 +00:00
try :
2019-11-04 16:55:03 +00:00
prefix_v6 = self . interface . machine_type . ip_type . prefix_v6 . encode ( ) . decode (
" utf-8 "
)
except AttributeError : # Prevents from crashing when there is no defined prefix_v6
2019-01-01 15:11:02 +00:00
prefix_v6 = None
2018-01-30 05:33:56 +00:00
if prefix_v6 :
2019-11-04 16:55:03 +00:00
if (
IPv6Address ( self . ipv6 . encode ( ) . decode ( " utf-8 " ) ) . exploded [ : 20 ]
!= IPv6Address ( prefix_v6 ) . exploded [ : 20 ]
) :
raise ValidationError (
_ (
" The v6 prefix is incorrect and "
" doesn ' t match the type associated "
" with the machine. "
)
)
2020-08-08 12:53:47 +00:00
self . validate_unique ( )
2018-01-30 02:01:06 +00:00
super ( Ipv6List , self ) . clean ( * args , * * kwargs )
def save ( self , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Force the call to clean before saving. """
2020-08-08 12:53:47 +00:00
self . clean ( )
2018-01-30 02:01:06 +00:00
super ( Ipv6List , self ) . save ( * args , * * kwargs )
2018-01-29 02:53:49 +00:00
def __str__ ( self ) :
return str ( self . ipv6 )
2019-10-02 20:48:33 +00:00
class Domain ( RevMixin , AclMixin , FieldPermissionModelMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Domain.
A and CNAME records at the same time : it enables to store aliases and
machine names , according to which fields are used .
Attributes :
interface_parent : the parent interface of the domain .
name : the name of the domain ( mandatory and unique ) .
extension : the extension of the domain .
cname : the CNAME record related to the domain .
ttl : the Time To Live of the domain .
"""
2016-11-01 01:14:06 +00:00
2017-10-15 20:10:33 +00:00
interface_parent = models . OneToOneField (
2019-11-04 16:55:03 +00:00
" Interface " , on_delete = models . CASCADE , blank = True , null = True
2017-10-15 20:10:33 +00:00
)
name = models . CharField (
2019-11-04 16:55:03 +00:00
help_text = _ ( " Mandatory and unique, must not contain dots. " ) , max_length = 255
2017-10-15 20:10:33 +00:00
)
2019-11-04 16:55:03 +00:00
extension = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
2017-10-15 20:10:33 +00:00
cname = models . ForeignKey (
2019-11-04 16:55:03 +00:00
" self " , null = True , blank = True , related_name = " related_domain "
2017-10-15 20:10:33 +00:00
)
2019-10-02 20:48:33 +00:00
ttl = models . PositiveIntegerField (
verbose_name = _ ( " Time To Live (TTL) " ) ,
2019-11-04 16:55:03 +00:00
default = 0 # 0 means that the re2o-service for DNS should retrieve the
2019-10-12 15:22:51 +00:00
# default TTL
2019-10-02 20:48:33 +00:00
)
2016-11-18 16:36:30 +00:00
class Meta :
2017-08-01 04:57:56 +00:00
unique_together = ( ( " name " , " extension " ) , )
2017-12-31 18:47:22 +00:00
permissions = (
2018-08-05 16:48:22 +00:00
( " view_domain " , _ ( " Can view a domain object " ) ) ,
2019-11-16 14:07:15 +00:00
( " change_ttl " , _ ( " Can change the TTL of a domain object " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " domain " )
verbose_name_plural = _ ( " domains " )
2016-11-18 16:36:30 +00:00
2017-07-23 02:22:22 +00:00
def get_extension ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the extension of the domain.
If it is an A record , get the extension of the parent interface .
If it is a CNAME record , get the extension of self .
"""
2017-07-23 02:22:22 +00:00
if self . interface_parent :
2019-03-03 16:28:33 +00:00
return self . interface_parent . machine_type . ip_type . extension
2019-11-04 16:55:03 +00:00
elif hasattr ( self , " extension " ) :
2017-07-23 02:22:22 +00:00
return self . extension
2017-08-01 04:57:56 +00:00
else :
return None
2017-07-23 02:22:22 +00:00
2016-12-24 17:07:09 +00:00
def clean ( self ) :
2020-04-29 22:17:01 +00:00
"""
Check if :
* the object is either an A or a CNAME record
* the CNAME record does not point to itself
* the name is not over 63 characters
* the name does not contain forbidden characters
* the couple ( name , extension ) is unique
"""
2017-08-01 04:57:56 +00:00
if self . get_extension ( ) :
2017-10-15 20:10:33 +00:00
self . extension = self . get_extension ( )
2016-12-24 17:07:09 +00:00
if self . interface_parent and self . cname :
2019-11-16 14:07:15 +00:00
raise ValidationError ( _ ( " You can ' t create a both A and CNAME record. " ) )
2017-10-15 20:10:33 +00:00
if self . cname == self :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2019-11-16 14:07:15 +00:00
_ ( " You can ' t create a CNAME record pointing to itself. " )
2019-11-04 16:55:03 +00:00
)
2020-04-18 17:17:04 +00:00
HOSTNAME_LABEL_PATTERN = re . compile ( r " (?!-)[a-z \ d-]+(?<!-)$ " )
self . name = self . name . lower ( )
if len ( self . name ) > 63 :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2020-04-18 17:17:04 +00:00
_ ( " The domain name %s is too long (over 63 characters). " ) % self . name
2019-11-04 16:55:03 +00:00
)
2020-04-18 17:17:04 +00:00
if not HOSTNAME_LABEL_PATTERN . match ( self . name ) :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2020-04-18 17:17:04 +00:00
_ ( " The domain name %s contains forbidden characters. " ) % self . name
2019-11-04 16:55:03 +00:00
)
2017-08-01 04:57:56 +00:00
self . validate_unique ( )
super ( Domain , self ) . clean ( )
2017-09-06 09:07:36 +00:00
@cached_property
def dns_entry ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the DNS entry of the domain. """
2017-09-06 09:07:36 +00:00
if self . cname :
2018-04-13 22:48:44 +00:00
return " {name} IN CNAME {cname} . " . format (
2019-11-04 16:55:03 +00:00
name = str ( self . name ) . ljust ( 15 ) , cname = str ( self . cname )
2018-04-13 22:48:44 +00:00
)
2016-11-01 01:14:06 +00:00
2017-07-23 02:22:22 +00:00
def save ( self , * args , * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Prevent from saving if the extension is invalid and force the call
to clean before saving .
"""
2017-08-01 04:57:56 +00:00
if not self . get_extension ( ) :
2018-08-05 16:48:22 +00:00
raise ValidationError ( _ ( " Invalid extension. " ) )
2020-08-08 12:53:47 +00:00
self . clean ( )
2017-07-23 02:22:22 +00:00
super ( Domain , self ) . save ( * args , * * kwargs )
2017-12-27 00:59:48 +00:00
@cached_property
def get_source_interface ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the source interface of the domain.
If it is an A record , get the parent interface .
If it is a CNAME record , follow recursively until reaching the related
A record and get the parent interface .
"""
2017-12-27 00:59:48 +00:00
if self . interface_parent :
return self . interface_parent
else :
2019-11-25 14:25:52 +00:00
return self . cname . get_source_interface
2017-12-27 00:59:48 +00:00
2018-04-14 18:19:02 +00:00
@staticmethod
def can_create ( user_request , interfaceid , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can create a domain for the given interface, or
that it is owned by the user .
Args :
user_request : the user requesting to create a domain .
interfaceid : the ID of the interface to be edited .
Returns :
A tuple indicating whether the user can create a domain for
the given interface and a message if not .
"""
2017-11-29 00:53:32 +00:00
try :
2017-11-30 20:38:16 +00:00
interface = Interface . objects . get ( pk = interfaceid )
2017-11-29 00:53:32 +00:00
except Interface . DoesNotExist :
2019-09-06 12:14:33 +00:00
return False , _ ( " Nonexistent interface. " ) , None
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.add_domain " ) :
max_lambdauser_aliases = preferences . models . OptionalMachine . get_cached_value (
" max_lambdauser_aliases "
)
2017-11-29 00:53:32 +00:00
if interface . machine . user != user_request :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You don ' t have the right to add an alias to a "
" machine of another user. "
) ,
( " machines.add_domain " , ) ,
2019-09-06 12:14:33 +00:00
)
2019-11-04 16:55:03 +00:00
if (
Domain . objects . filter (
2018-08-05 16:48:22 +00:00
cname__in = Domain . objects . filter (
2019-11-04 16:55:03 +00:00
interface_parent__in = ( interface . machine . user . user_interfaces ( ) )
2018-08-05 16:48:22 +00:00
)
2019-11-04 16:55:03 +00:00
) . count ( )
> = max_lambdauser_aliases
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You reached the maximum number of alias that "
" you are allowed to create yourself ( %s ). "
% max_lambdauser_aliases
) ,
( " machines.add_domain " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-11-29 00:53:32 +00:00
2018-04-14 18:19:02 +00:00
def can_edit ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can edit the current domain, or that the related
interface is owned by the user .
Args :
user_request : the user requesting to edit self .
Returns :
A tuple indicating whether the user can edit self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.change_domain " )
and self . get_source_interface . machine . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You don ' t have the right to edit an alias of a "
" machine of another user. "
) ,
( " machines.change_domain " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-11-29 23:45:53 +00:00
2018-04-14 18:19:02 +00:00
def can_delete ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can delete the current domain, or that the related
interface is owned by the user .
Args :
user_request : the user requesting to delete self .
Returns :
A tuple indicating whether the user can delete self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.delete_domain " )
and self . get_source_interface . machine . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2019-11-04 16:55:03 +00:00
_ (
" You don ' t have the right to delete an alias of a "
" machine of another user. "
) ,
( " machines.delete_domain " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 15:32:43 +00:00
2018-04-14 18:19:02 +00:00
def can_view ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can view the current domain, or that the related
interface is owned by the user .
Args :
user_request : the user requesting to view self .
Returns :
A tuple indicating whether the user can view self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if (
not user_request . has_perm ( " machines.view_domain " )
and self . get_source_interface . machine . user != user_request
) :
2019-09-06 12:14:33 +00:00
return (
False ,
2020-04-30 20:27:21 +00:00
_ ( " You don ' t have the right to view other machines than " " yours. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.view_domain " , ) ,
2019-09-06 12:14:33 +00:00
)
return True , None , None
2017-12-03 16:43:07 +00:00
2019-10-02 20:48:33 +00:00
@staticmethod
def can_change_ttl ( user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can change the TTL of the domain. """
2019-11-04 16:55:03 +00:00
can = user_request . has_perm ( " machines.change_ttl " )
2019-10-02 20:48:33 +00:00
return (
can ,
2019-11-04 16:55:03 +00:00
_ ( " You don ' t have the right to change the domain ' s TTL. " )
if not can
else None ,
( " machines.change_ttl " , ) ,
2019-10-02 20:48:33 +00:00
)
2016-11-01 01:14:06 +00:00
def __str__ ( self ) :
2017-08-06 18:00:29 +00:00
return str ( self . name ) + str ( self . extension )
2016-11-01 01:14:06 +00:00
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class IpList ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" IPv4 addresses list.
Attributes :
ipv4 : the IPv4 address of the list .
ip_type : the IP type of the list .
"""
2016-11-01 01:14:06 +00:00
2019-11-04 16:55:03 +00:00
ipv4 = models . GenericIPAddressField ( protocol = " IPv4 " , unique = True )
ip_type = models . ForeignKey ( " IpType " , on_delete = models . CASCADE )
2017-07-21 03:06:53 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_iplist " , _ ( " Can view an IPv4 addresses list object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " IPv4 addresses list " )
verbose_name_plural = _ ( " IPv4 addresses lists " )
2017-12-31 18:47:22 +00:00
2017-07-21 03:06:53 +00:00
@cached_property
def need_infra ( self ) :
2020-04-29 22:17:01 +00:00
""" Check if the ' infra ' right is required to assign this IP address.
"""
2017-07-21 03:06:53 +00:00
return self . ip_type . need_infra
def clean ( self ) :
2020-04-29 22:17:01 +00:00
""" Clean self.
Raises :
ValidationError : if the IPv4 address and the IP type of self do not
match .
"""
2017-07-21 03:06:53 +00:00
if not str ( self . ipv4 ) in self . ip_type . ip_set_as_str :
2019-11-04 16:55:03 +00:00
raise ValidationError (
2019-11-16 14:07:15 +00:00
_ ( " The IPv4 address and the range of the IP type don ' t match. " )
2019-11-04 16:55:03 +00:00
)
2017-07-21 03:06:53 +00:00
return
def save ( self , * args , * * kwargs ) :
self . clean ( )
super ( IpList , self ) . save ( * args , * * kwargs )
2016-07-03 14:49:29 +00:00
2020-12-31 13:55:10 +00:00
@classmethod
def can_list ( cls , user_request , * _args , * * _kwargs ) :
""" Only privilged users can list all ipv4.
Others can list Ipv4 related with unprivileged type .
: param user_request : The user who wants to view the list .
: return : True if the user can view the list and an explanation
message .
"""
can , _message , _group = IpType . can_use_all ( user_request )
if can :
return (
True ,
None ,
None ,
cls . objects . all ( )
)
else :
return (
2021-01-02 22:03:13 +00:00
True ,
2020-12-31 13:55:10 +00:00
_ ( " You don ' t have the right to use all machine types. " ) ,
( " machines.use_all_machinetype " , ) ,
cls . objects . filter (
ip_type__in = IpType . objects . filter ( need_infra = False )
) ,
)
2016-07-03 14:49:29 +00:00
def __str__ ( self ) :
2016-07-04 00:48:24 +00:00
return self . ipv4
2017-10-15 20:10:33 +00:00
2018-06-23 14:39:03 +00:00
class Role ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Role.
It enabled to automate the generation of server configurations .
Attributes :
role_type : the type of the role ( name provided by the user ) .
servers : the servers related to the role .
specific_role : the specific role , e . g . DHCP server , LDAP server etc .
2018-07-17 19:26:42 +00:00
"""
2018-06-23 14:39:03 +00:00
2018-07-11 16:49:27 +00:00
ROLE = (
2019-11-04 16:55:03 +00:00
( " dhcp-server " , _ ( " DHCP server " ) ) ,
( " switch-conf-server " , _ ( " Switches configuration server " ) ) ,
( " dns-recursive-server " , _ ( " Recursive DNS server " ) ) ,
( " ntp-server " , _ ( " NTP server " ) ) ,
( " radius-server " , _ ( " RADIUS server " ) ) ,
( " log-server " , _ ( " Log server " ) ) ,
( " ldap-master-server " , _ ( " LDAP master server " ) ) ,
( " ldap-backup-server " , _ ( " LDAP backup server " ) ) ,
( " smtp-server " , _ ( " SMTP server " ) ) ,
( " postgresql-server " , _ ( " postgreSQL server " ) ) ,
( " mysql-server " , _ ( " mySQL server " ) ) ,
( " sql-client " , _ ( " SQL client " ) ) ,
( " gateway " , _ ( " Gateway " ) ) ,
2018-07-11 16:49:27 +00:00
)
2018-06-23 14:39:03 +00:00
role_type = models . CharField ( max_length = 255 , unique = True )
2019-11-04 16:55:03 +00:00
servers = models . ManyToManyField ( " Interface " )
specific_role = models . CharField ( choices = ROLE , null = True , blank = True , max_length = 32 )
2018-06-23 14:39:03 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_role " , _ ( " Can view a role object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " server role " )
verbose_name_plural = _ ( " server roles " )
2018-06-23 14:39:03 +00:00
2018-07-11 17:46:13 +00:00
@classmethod
def interface_for_roletype ( cls , roletype ) :
""" Return interfaces for a roletype """
2019-11-04 16:55:03 +00:00
return Interface . objects . filter ( role = cls . objects . filter ( specific_role = roletype ) )
2018-07-11 17:46:13 +00:00
2018-07-11 22:11:55 +00:00
@classmethod
def all_interfaces_for_roletype ( cls , roletype ) :
""" Return all interfaces for a roletype """
return Interface . objects . filter (
machine__interface__role = cls . objects . filter ( specific_role = roletype )
)
2018-07-11 17:46:13 +00:00
@classmethod
def interface_for_roletype ( cls , roletype ) :
""" Return interfaces for a roletype """
return Interface . objects . filter ( role = cls . objects . filter ( specific_role = roletype ) )
2018-06-23 14:39:03 +00:00
def save ( self , * args , * * kwargs ) :
super ( Role , self ) . save ( * args , * * kwargs )
def __str__ ( self ) :
return str ( self . role_type )
2018-07-17 19:26:42 +00:00
2018-03-31 15:18:39 +00:00
class Service ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Service (DHCP, DNS...).
Attributes :
service_type : the type of the service ( provided by the user ) .
min_time_regen : the minimal time before regeneration .
regular_time_regen : the maximal time before regeneration .
servers : the servers related to the service .
"""
2017-10-27 20:12:55 +00:00
2017-08-08 04:56:19 +00:00
service_type = models . CharField ( max_length = 255 , blank = True , unique = True )
2017-10-15 20:10:33 +00:00
min_time_regen = models . DurationField (
default = timedelta ( minutes = 1 ) ,
2019-11-04 16:55:03 +00:00
help_text = _ ( " Minimal time before regeneration of the service. " ) ,
2017-10-15 20:10:33 +00:00
)
regular_time_regen = models . DurationField (
default = timedelta ( hours = 1 ) ,
2019-11-04 16:55:03 +00:00
help_text = _ ( " Maximal time before regeneration of the service. " ) ,
2017-10-15 20:10:33 +00:00
)
2019-11-04 16:55:03 +00:00
servers = models . ManyToManyField ( " Interface " , through = " Service_link " )
2017-08-08 04:56:19 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
2019-11-04 16:55:03 +00:00
permissions = ( ( " view_service " , _ ( " Can view a service object " ) ) , )
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " service to generate (DHCP, DNS, ...) " )
verbose_name_plural = _ ( " services to generate (DHCP, DNS, ...) " )
2017-12-31 18:47:22 +00:00
2017-08-08 04:56:19 +00:00
def ask_regen ( self ) :
2020-04-29 22:17:01 +00:00
""" Set the demand for regen to True for the current Service (self). """
2019-11-04 16:55:03 +00:00
Service_link . objects . filter ( service = self ) . exclude ( asked_regen = True ) . update (
asked_regen = True
)
2017-08-18 22:01:06 +00:00
return
2017-08-08 04:56:19 +00:00
def process_link ( self , servers ) :
2020-04-29 22:17:01 +00:00
""" Process the links between services and servers.
Django does not create the ManyToMany relations with explicit
intermediate table .
"""
2019-11-04 16:55:03 +00:00
for serv in servers . exclude ( pk__in = Interface . objects . filter ( service = self ) ) :
2017-08-08 04:56:19 +00:00
link = Service_link ( service = self , server = serv )
link . save ( )
2019-11-04 16:55:03 +00:00
Service_link . objects . filter ( service = self ) . exclude ( server__in = servers ) . delete ( )
2017-08-08 04:56:19 +00:00
return
def save ( self , * args , * * kwargs ) :
super ( Service , self ) . save ( * args , * * kwargs )
def __str__ ( self ) :
return str ( self . service_type )
2017-10-15 20:10:33 +00:00
2017-08-08 17:40:30 +00:00
def regen ( service ) :
2020-04-29 22:17:01 +00:00
""" Ask regeneration for the given service.
Args :
service : the service to be regenerated .
"""
2018-05-14 21:58:05 +00:00
obj = Service . objects . filter ( service_type = service )
if obj :
obj [ 0 ] . ask_regen ( )
2017-08-08 17:40:30 +00:00
return
2017-10-15 20:10:33 +00:00
2018-03-31 15:18:39 +00:00
class Service_link ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Service server link.
Attributes :
service : the service related to the link .
server : the server related to the link .
last_regen : datetime , the last time of the regeneration .
asked_regen : whether regeneration has been asked .
"""
2017-10-27 20:12:55 +00:00
2019-11-04 16:55:03 +00:00
service = models . ForeignKey ( " Service " , on_delete = models . CASCADE )
server = models . ForeignKey ( " Interface " , on_delete = models . CASCADE )
2017-08-08 04:56:19 +00:00
last_regen = models . DateTimeField ( auto_now_add = True )
asked_regen = models . BooleanField ( default = False )
2018-05-25 20:10:31 +00:00
class Meta :
permissions = (
2018-08-05 16:48:22 +00:00
( " view_service_link " , _ ( " Can view a service server link object " ) ) ,
2018-05-25 20:10:31 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " link between service and server " )
verbose_name_plural = _ ( " links between service and server " )
2018-05-25 20:10:31 +00:00
2017-08-08 17:40:30 +00:00
def done_regen ( self ) :
2020-04-29 22:17:01 +00:00
""" Update the regen information when the server regenerated its
service . """
2017-08-08 17:40:30 +00:00
self . last_regen = timezone . now ( )
self . asked_regen = False
self . save ( )
2017-08-08 04:56:19 +00:00
2018-05-26 21:08:03 +00:00
@property
2017-08-08 04:56:19 +00:00
def need_regen ( self ) :
2020-04-29 22:17:01 +00:00
""" Decide if the minimal time elapsed is enough to regenerate the
service . """
2017-10-15 20:10:33 +00:00
return bool (
2019-11-04 16:55:03 +00:00
(
self . asked_regen
and ( self . last_regen + self . service . min_time_regen ) < timezone . now ( )
)
or ( self . last_regen + self . service . regular_time_regen ) < timezone . now ( )
2017-10-15 20:10:33 +00:00
)
2017-08-08 04:56:19 +00:00
2018-05-26 21:08:03 +00:00
@need_regen.setter
def need_regen ( self , value ) :
2020-04-29 22:17:01 +00:00
""" Force to set the need_regen value.
True means a regen is asked and False means a regen has been done .
2018-05-26 21:08:03 +00:00
2020-04-29 22:17:01 +00:00
Args :
value : bool , the value to set .
2018-05-26 21:08:03 +00:00
"""
if not value :
self . last_regen = timezone . now ( )
self . asked_regen = value
self . save ( )
2017-08-08 04:56:19 +00:00
def __str__ ( self ) :
return str ( self . server ) + " " + str ( self . service )
2017-09-28 15:19:33 +00:00
2018-03-31 15:18:39 +00:00
class OuverturePortList ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Ports opening list.
Attributes :
name : the name of the ports configuration .
"""
2017-10-27 20:12:55 +00:00
2017-10-15 20:10:33 +00:00
name = models . CharField (
2019-11-04 16:55:03 +00:00
help_text = _ ( " Name of the ports configuration " ) , max_length = 255
2017-10-15 20:10:33 +00:00
)
2017-09-28 15:19:33 +00:00
2017-12-31 18:47:22 +00:00
class Meta :
permissions = (
2020-04-30 20:27:21 +00:00
( " view_ouvertureportlist " , _ ( " Can view a ports opening list " " object " ) ) ,
2017-12-31 18:47:22 +00:00
)
2018-08-05 16:48:22 +00:00
verbose_name = _ ( " ports opening list " )
verbose_name_plural = _ ( " ports opening lists " )
2017-12-31 18:47:22 +00:00
2018-04-14 18:19:02 +00:00
def can_delete ( self , user_request , * _args , * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Check if the user can delete the current ports opening list (self).
Args :
user_request : the user requesting to delete self .
Returns :
A tuple indicating whether the user can delete self and a
message if not .
"""
2019-11-04 16:55:03 +00:00
if not user_request . has_perm ( " machines.delete_ouvertureportlist " ) :
2019-09-06 12:14:33 +00:00
return (
False ,
_ ( " You don ' t have the right to delete a ports opening list. " ) ,
2019-11-04 16:55:03 +00:00
( " machines.delete_ouvertureportlist " , ) ,
2019-09-06 12:14:33 +00:00
)
2017-12-09 01:15:11 +00:00
if self . interface_set . all ( ) :
2019-09-06 12:14:33 +00:00
return False , _ ( " This ports opening list is used. " ) , None
return True , None , None
2017-12-03 15:32:43 +00:00
2017-09-28 15:19:33 +00:00
def __str__ ( self ) :
2017-10-01 19:57:10 +00:00
return self . name
2017-09-28 15:19:33 +00:00
2017-10-01 09:39:39 +00:00
def tcp_ports_in ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of ports opened in TCP IN of the current ports opening
list . """
2017-10-15 20:10:33 +00:00
return self . ouvertureport_set . filter (
2019-11-04 16:55:03 +00:00
protocole = OuverturePort . TCP , io = OuverturePort . IN
2017-10-15 20:10:33 +00:00
)
2017-10-01 09:39:39 +00:00
def udp_ports_in ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of ports opened in UDP IN of the current ports opening
list . """
2017-10-15 20:10:33 +00:00
return self . ouvertureport_set . filter (
2019-11-04 16:55:03 +00:00
protocole = OuverturePort . UDP , io = OuverturePort . IN
2017-10-15 20:10:33 +00:00
)
2017-10-01 09:39:39 +00:00
def tcp_ports_out ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of ports opened in TCP OUT of the current ports opening
list . """
2017-10-15 20:10:33 +00:00
return self . ouvertureport_set . filter (
2019-11-04 16:55:03 +00:00
protocole = OuverturePort . TCP , io = OuverturePort . OUT
2017-10-15 20:10:33 +00:00
)
2017-10-01 09:39:39 +00:00
def udp_ports_out ( self ) :
2020-04-29 22:17:01 +00:00
""" Get the list of ports opened in UDP OUT of the current ports opening
list . """
2017-10-15 20:10:33 +00:00
return self . ouvertureport_set . filter (
2019-11-04 16:55:03 +00:00
protocole = OuverturePort . UDP , io = OuverturePort . OUT
2017-10-15 20:10:33 +00:00
)
2017-10-01 09:39:39 +00:00
2017-09-29 20:28:48 +00:00
2018-03-31 15:18:39 +00:00
class OuverturePort ( RevMixin , AclMixin , models . Model ) :
2020-04-29 22:17:01 +00:00
""" Ports opening.
The ports of the range are between begin and end ( included ) .
If begin == end , then it represents a single port .
The ports are limited to be between 0 and 65535 , as defined in the RFC .
Attributes :
begin : the number of the first port of the ports opening .
end : the number of the last port of the ports opening .
port_list : the ports opening list ( configuration for opened ports ) of
the ports opening .
protocole : the protocol of the ports opening .
io : the direction of communication , IN or OUT .
2017-09-28 15:19:33 +00:00
"""
2017-10-27 20:12:55 +00:00
2019-11-04 16:55:03 +00:00
TCP = " T "
UDP = " U "
IN = " I "
OUT = " O "
2017-10-15 18:37:21 +00:00
begin = models . PositiveIntegerField ( validators = [ MaxValueValidator ( 65535 ) ] )
end = models . PositiveIntegerField ( validators = [ MaxValueValidator ( 65535 ) ] )
2019-11-04 16:55:03 +00:00
port_list = models . ForeignKey ( " OuverturePortList " , on_delete = models . CASCADE )
2017-09-28 15:19:33 +00:00
protocole = models . CharField (
2019-11-04 16:55:03 +00:00
max_length = 1 , choices = ( ( TCP , " TCP " ) , ( UDP , " UDP " ) ) , default = TCP
2017-10-01 09:39:39 +00:00
)
2019-11-04 16:55:03 +00:00
io = models . CharField ( max_length = 1 , choices = ( ( IN , " IN " ) , ( OUT , " OUT " ) ) , default = OUT )
2018-09-24 17:31:23 +00:00
2018-08-05 16:48:22 +00:00
class Meta :
2019-01-08 23:39:31 +00:00
verbose_name = _ ( " ports opening " )
verbose_name_plural = _ ( " ports openings " )
2017-09-28 15:19:33 +00:00
def __str__ ( self ) :
2017-10-15 20:10:33 +00:00
if self . begin == self . end :
2017-09-29 20:28:48 +00:00
return str ( self . begin )
2019-11-04 16:55:03 +00:00
return " : " . join ( [ str ( self . begin ) , str ( self . end ) ] )
2017-09-28 15:19:33 +00:00
2017-09-30 08:04:18 +00:00
def show_port ( self ) :
2020-04-29 22:17:01 +00:00
""" Format the ports opening by calling str. """
2017-09-30 08:04:18 +00:00
return str ( self )
2017-09-28 15:19:33 +00:00
2017-03-09 23:05:53 +00:00
@receiver ( post_save , sender = Machine )
2018-04-15 01:00:05 +00:00
def machine_post_save ( * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Synchronise LDAP and regen firewall/DHCP after a machine is edited. """
2019-11-04 16:55:03 +00:00
user = kwargs [ " instance " ] . user
2021-01-12 18:08:17 +00:00
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
2019-11-04 16:55:03 +00:00
regen ( " dhcp " )
regen ( " mac_ip_list " )
2017-03-09 23:05:53 +00:00
2017-10-15 20:10:33 +00:00
2017-03-09 23:05:53 +00:00
@receiver ( post_delete , sender = Machine )
2018-04-15 01:00:05 +00:00
def machine_post_delete ( * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Synchronise LDAP and regen firewall/DHCP after a machine is deleted. """
2019-11-04 16:55:03 +00:00
machine = kwargs [ " instance " ]
2017-03-09 23:05:53 +00:00
user = machine . user
2021-01-12 18:08:17 +00:00
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
2019-11-04 16:55:03 +00:00
regen ( " dhcp " )
regen ( " mac_ip_list " )
2016-07-25 21:54:40 +00:00
2017-10-15 20:10:33 +00:00
2016-07-25 21:54:40 +00:00
@receiver ( post_save , sender = Interface )
2018-04-15 01:00:05 +00:00
def interface_post_save ( * * kwargs ) :
2020-06-09 09:27:35 +00:00
""" Synchronise LDAP, regen firewall/DHCP after an interface is edited
and update associated domains
2020-04-29 22:17:01 +00:00
"""
2019-11-04 16:55:03 +00:00
interface = kwargs [ " instance " ]
2018-01-30 05:33:56 +00:00
interface . sync_ipv6 ( )
2017-07-21 04:49:39 +00:00
user = interface . machine . user
2021-01-12 18:08:17 +00:00
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
2017-10-02 02:19:07 +00:00
# Regen services
2019-11-04 16:55:03 +00:00
regen ( " dhcp " )
regen ( " mac_ip_list " )
2020-06-09 09:27:35 +00:00
# Update associated domains
for domain in interface . all_domains ( ) :
domain . clean ( )
domain . save ( )
2016-07-25 21:54:40 +00:00
2017-10-15 20:10:33 +00:00
2016-07-25 21:54:40 +00:00
@receiver ( post_delete , sender = Interface )
2018-04-15 01:00:05 +00:00
def interface_post_delete ( * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Synchronise LDAP and regen firewall/DHCP after an interface is deleted.
"""
2019-11-04 16:55:03 +00:00
interface = kwargs [ " instance " ]
2016-12-14 17:09:24 +00:00
user = interface . machine . user
2021-01-12 18:08:17 +00:00
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
2016-12-14 17:09:24 +00:00
2017-10-15 20:10:33 +00:00
2017-07-21 03:06:53 +00:00
@receiver ( post_save , sender = IpType )
2018-04-15 01:00:05 +00:00
def iptype_post_save ( * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Generate the IP objects after an IP type is edited. """
2019-11-04 16:55:03 +00:00
iptype = kwargs [ " instance " ]
2017-08-28 23:04:15 +00:00
iptype . gen_ip_range ( )
2018-01-30 03:51:15 +00:00
iptype . check_replace_prefixv6 ( )
2020-06-09 09:27:35 +00:00
for machinetype in iptype . all_machine_types ( ) :
machinetype . save ( )
2017-07-21 03:06:53 +00:00
2017-10-15 20:10:33 +00:00
2017-07-23 03:03:56 +00:00
@receiver ( post_save , sender = MachineType )
2018-04-15 01:00:05 +00:00
def machinetype_post_save ( * * kwargs ) :
2020-04-29 22:17:01 +00:00
""" Update the interfaces after the machine type is changed (change the
parent IP type ) .
"""
2019-11-04 16:55:03 +00:00
machinetype = kwargs [ " instance " ]
2020-06-09 21:23:48 +00:00
machinetype . update_domains ( )
2017-09-01 16:47:34 +00:00
2017-10-15 20:10:33 +00:00
2017-09-01 16:47:34 +00:00
@receiver ( post_save , sender = Domain )
2018-04-15 01:00:05 +00:00
def domain_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a domain is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-01 16:47:34 +00:00
2017-10-15 20:10:33 +00:00
2017-09-05 16:23:25 +00:00
@receiver ( post_delete , sender = Domain )
2018-04-15 01:00:05 +00:00
def domain_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a domain is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2017-10-15 20:10:33 +00:00
2017-09-08 23:07:28 +00:00
@receiver ( post_save , sender = Extension )
2018-04-15 01:00:05 +00:00
def extension_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an extension is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-08 23:07:28 +00:00
2017-10-15 20:10:33 +00:00
2017-09-08 23:07:28 +00:00
@receiver ( post_delete , sender = Extension )
2020-04-30 10:57:18 +00:00
def extension_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an extension is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-08 23:07:28 +00:00
2017-10-15 20:10:33 +00:00
2017-10-19 23:52:38 +00:00
@receiver ( post_save , sender = SOA )
2018-04-15 01:00:05 +00:00
def soa_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a SOA record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-10-19 23:52:38 +00:00
@receiver ( post_delete , sender = SOA )
2018-04-15 01:00:05 +00:00
def soa_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a SOA record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-10-19 23:52:38 +00:00
2017-09-05 16:23:25 +00:00
@receiver ( post_save , sender = Mx )
2018-04-15 01:00:05 +00:00
def mx_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an MX record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2017-10-15 20:10:33 +00:00
2017-09-05 16:23:25 +00:00
@receiver ( post_delete , sender = Mx )
2018-04-15 01:00:05 +00:00
def mx_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an MX record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2017-10-15 20:10:33 +00:00
2017-09-05 16:23:25 +00:00
@receiver ( post_save , sender = Ns )
2018-04-15 01:00:05 +00:00
def ns_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an NS record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2017-10-15 20:10:33 +00:00
2017-09-05 16:23:25 +00:00
@receiver ( post_delete , sender = Ns )
2018-04-15 01:00:05 +00:00
def ns_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an NS record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2017-10-15 20:10:33 +00:00
2017-11-15 14:17:22 +00:00
@receiver ( post_save , sender = Txt )
2018-04-15 01:00:05 +00:00
def text_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a TXT record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-09-05 16:23:25 +00:00
2018-07-23 21:19:19 +00:00
2017-11-15 14:17:22 +00:00
@receiver ( post_delete , sender = Txt )
2018-04-15 01:00:05 +00:00
def text_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a TXT record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-11-16 01:45:49 +00:00
2018-07-23 21:19:19 +00:00
2018-06-25 14:50:45 +00:00
@receiver ( post_save , sender = DName )
def dname_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a DNAME record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2018-06-25 14:50:45 +00:00
2018-07-23 21:19:19 +00:00
2018-06-25 14:50:45 +00:00
@receiver ( post_delete , sender = DName )
2018-07-23 21:19:19 +00:00
def dname_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after a DNAME record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2018-06-25 14:50:45 +00:00
2017-11-16 01:45:49 +00:00
@receiver ( post_save , sender = Srv )
2018-04-15 01:00:05 +00:00
def srv_post_save ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an SRV record is edited. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )
2017-11-16 01:45:49 +00:00
@receiver ( post_delete , sender = Srv )
2018-04-15 01:00:05 +00:00
def srv_post_delete ( * * _kwargs ) :
2020-04-29 22:17:01 +00:00
""" Regenerate the DNS after an SRV record is deleted. """
2019-11-04 16:55:03 +00:00
regen ( " dns " )