models.py 12.2 KB
Newer Older
Őry Máté committed
1 2
# -*- coding: utf8 -*-

Őry Máté committed
3
from django.contrib.auth.models import User
Őry Máté committed
4
from django.db import models
5
from django.forms import fields, ValidationError
Őry Máté committed
6
from django.utils.translation import ugettext_lazy as _
Őry Máté committed
7
from firewall.fields import *
8
from south.modelsinspector import add_introspection_rules
9
from django.core.validators import MinValueValidator, MaxValueValidator
Őry Máté committed
10
from cloud.settings import firewall_settings as settings
11 12
from django.utils.ipv6 import is_valid_ipv6_address
import re
Őry Máté committed
13 14

class Rule(models.Model):
x committed
15 16 17
    CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan'))
    CHOICES_proto = (('tcp', 'tcp'), ('udp', 'udp'), ('icmp', 'icmp'))
    CHOICES_dir = (('0', 'out'), ('1', 'in'))
18

x committed
19 20
    direction = models.CharField(max_length=1, choices=CHOICES_dir, blank=False)
    description = models.TextField(blank=True)
Bach Dániel committed
21
    foreign_network = models.ForeignKey('VlanGroup', related_name="ForeignRules")
x committed
22 23 24 25 26 27 28 29 30
    dport = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(1), MaxValueValidator(65535)])
    sport = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(1), MaxValueValidator(65535)])
    proto = models.CharField(max_length=10, choices=CHOICES_proto, blank=True, null=True)
    extra = models.TextField(blank=True)
    accept = models.BooleanField(default=False)
    owner = models.ForeignKey(User, blank=True, null=True)
    r_type = models.CharField(max_length=10, choices=CHOICES_type)
    nat = models.BooleanField(default=False)
    nat_dport = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(1), MaxValueValidator(65535)])
Őry Máté committed
31 32
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
x committed
33

Bach Dániel committed
34 35 36 37 38 39
    vlan = models.ForeignKey('Vlan', related_name="rules", blank=True, null=True)
    vlangroup = models.ForeignKey('VlanGroup', related_name="rules", blank=True, null=True)
    host = models.ForeignKey('Host', related_name="rules", blank=True, null=True)
    hostgroup = models.ForeignKey('Group', related_name="rules", blank=True, null=True)
    firewall = models.ForeignKey('Firewall', related_name="rules", blank=True, null=True)

x committed
40
    def __unicode__(self):
root committed
41
        return self.desc()
Őry Máté committed
42

Bach Dániel committed
43 44 45 46 47 48 49
    def clean(self):
        count = 0
        for field in [self.vlan, self.vlangroup, self.host, self.hostgroup, self.firewall]:
             if field is None:
                 count = count + 1
        if count != 4:
            raise ValidationError('jaj')
x committed
50 51 52 53 54 55 56 57 58

    def desc(self):
        para = u""
        if(self.dport):
            para = "dport=%s %s" % (self.dport, para)
        if(self.sport):
            para = "sport=%s %s" % (self.sport, para)
        if(self.proto):
            para = "proto=%s %s" % (self.proto, para)
Bach Dániel committed
59
        return u'[' + self.r_type + u'] ' + (unicode(self.foreign_network) + u' ▸ ' + self.r_type if self.direction=='1' else self.r_type + u' ▸ ' + unicode(self.foreign_network)) + u' ' + para + u' ' +self.description
Őry Máté committed
60 61 62 63

class Vlan(models.Model):
    vid = models.IntegerField(unique=True)
    name = models.CharField(max_length=20, unique=True, validators=[val_alfanum])
64 65
    prefix4 = models.IntegerField(default=16)
    prefix6 = models.IntegerField(default=80)
Őry Máté committed
66 67 68 69 70
    interface = models.CharField(max_length=20, unique=True)
    net4 = models.GenericIPAddressField(protocol='ipv4', unique=True)
    net6 = models.GenericIPAddressField(protocol='ipv6', unique=True)
    ipv4 = models.GenericIPAddressField(protocol='ipv4', unique=True)
    ipv6 = models.GenericIPAddressField(protocol='ipv6', unique=True)
root committed
71 72
    snat_ip = models.GenericIPAddressField(protocol='ipv4', blank=True, null=True)
    snat_to = models.ManyToManyField('self', symmetrical=False, blank=True, null=True)
Őry Máté committed
73 74
    description = models.TextField(blank=True)
    comment = models.TextField(blank=True)
75 76
    domain = models.ForeignKey('Domain')
    reverse_domain = models.TextField(validators=[val_reverse_domain])
Őry Máté committed
77
    dhcp_pool = models.TextField(blank=True)
Őry Máté committed
78
    created_at = models.DateTimeField(auto_now_add=True)
79
    owner = models.ForeignKey(User, blank=True, null=True)
Őry Máté committed
80
    modified_at = models.DateTimeField(auto_now=True)
81

Őry Máté committed
82 83
    def __unicode__(self):
        return self.name
84

Őry Máté committed
85
    def net_ipv6(self):
x committed
86
        return self.net6 + "/" + unicode(self.prefix6)
87

Őry Máté committed
88
    def net_ipv4(self):
x committed
89
        return self.net4 + "/" + unicode(self.prefix4)
Bach Dániel committed
90 91 92 93 94 95 96 97 98 99 100

class VlanGroup(models.Model):
    name = models.CharField(max_length=20, unique=True)
    vlans = models.ManyToManyField('Vlan', symmetrical=False, blank=True, null=True)
    description = models.TextField(blank=True)
    owner = models.ForeignKey(User, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.name
Őry Máté committed
101 102 103

class Group(models.Model):
    name = models.CharField(max_length=20, unique=True)
Bach Dániel committed
104 105
    description = models.TextField(blank=True)
    owner = models.ForeignKey(User, blank=True, null=True)
Őry Máté committed
106 107
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
108

Őry Máté committed
109 110 111 112
    def __unicode__(self):
        return self.name

class Host(models.Model):
x committed
113
    hostname = models.CharField(max_length=40, unique=True, validators=[val_alfanum])
114
    reverse = models.CharField(max_length=40, validators=[val_domain], blank=True, null=True)
Őry Máté committed
115 116
    mac = MACAddressField(unique=True)
    ipv4 = models.GenericIPAddressField(protocol='ipv4', unique=True)
117
    pub_ipv4 = models.GenericIPAddressField(protocol='ipv4', blank=True, null=True)
118
    ipv6 = models.GenericIPAddressField(protocol='ipv6', unique=True, blank=True, null=True)
119
    shared_ip = models.BooleanField(default=False)
Őry Máté committed
120 121 122 123 124 125
    description = models.TextField(blank=True)
    comment = models.TextField(blank=True)
    location = models.TextField(blank=True)
    vlan = models.ForeignKey('Vlan')
    owner = models.ForeignKey(User)
    groups = models.ManyToManyField('Group', symmetrical=False, blank=True, null=True)
Őry Máté committed
126 127
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
128

Őry Máté committed
129 130
    def __unicode__(self):
        return self.hostname
131

Őry Máté committed
132
    def save(self, *args, **kwargs):
133
        id = self.id
134
        if not self.id and self.ipv6 == "auto":
Őry Máté committed
135
            self.ipv6 = ipv4_2_ipv6(self.ipv4)
x committed
136 137
        if not self.shared_ip and self.pub_ipv4 and Host.objects.exclude(id=self.id).filter(pub_ipv4=self.pub_ipv4):
            raise ValidationError("Ha a shared_ip be van pipalva, akkor egyedinek kell lennie a pub_ipv4-nek!")
x committed
138 139
        if Host.objects.exclude(id=self.id).filter(pub_ipv4=self.ipv4):
            raise ValidationError("Egy masik host natolt cimet nem hasznalhatod sajat ipv4-nek")
Bach Dániel committed
140
        self.full_clean()
Őry Máté committed
141
        super(Host, self).save(*args, **kwargs)
142 143
        if(id is None):
            Record(domain=self.vlan.domain, host=self, type='A', owner=self.owner).save()
Bach Dániel committed
144
            if self.ipv6:
145
                Record(domain=self.vlan.domain, host=self, type='AAAA', owner=self.owner).save()
Bach Dániel committed
146

Őry Máté committed
147
    def enable_net(self):
x committed
148
        self.groups.add(Group.objects.get(name="netezhet"))
149

Őry Máté committed
150
    def add_port(self, proto, public, private):
x committed
151
        proto = "tcp" if (proto == "tcp") else "udp"
152
        if public < 1024:
x committed
153 154 155 156
            raise ValidationError("Csak az 1024 feletti portok hasznalhatok")
        for host in Host.objects.filter(pub_ipv4=self.pub_ipv4):
            if host.rules.filter(nat=True, proto=proto, dport=public):
                raise ValidationError("A %s %s port mar hasznalva" % (proto, public))
x committed
157
        rule = Rule(direction='1', owner=self.owner, dport=public, proto=proto, nat=True, accept=True, r_type="host", nat_dport=private, host=self, foreign_network=VlanGroup.objects.get(name=settings["default_vlangroup"]))
x committed
158 159
        rule.full_clean()
        rule.save()
160

Őry Máté committed
161
    def del_port(self, proto, public):
x committed
162
        self.rules.filter(owner=self.owner, proto=proto, nat=True, dport=public).delete()
163

Őry Máté committed
164
    def list_ports(self):
x committed
165 166 167 168
        retval = []
        for rule in self.rules.filter(owner=self.owner, nat=True):
            retval.append({'proto': rule.proto, 'public': rule.dport, 'private': rule.nat_dport})
        return retval
169

Őry Máté committed
170
    def del_rules(self):
x committed
171
        self.rules.filter(owner=self.owner).delete()
Őry Máté committed
172

173
    def get_fqdn(self):
174
        return self.hostname + u'.' + unicode(self.vlan.domain)
Őry Máté committed
175

176

Őry Máté committed
177 178
class Firewall(models.Model):
    name = models.CharField(max_length=20, unique=True)
179

Őry Máté committed
180 181
    def __unicode__(self):
        return self.name
Őry Máté committed
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
class Domain(models.Model):
    name = models.CharField(max_length=40, validators=[val_domain])
    owner = models.ForeignKey(User)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
    ttl = models.IntegerField(default=600)
    description = models.TextField(blank=True)

    def __unicode__(self):
        return self.name

class Record(models.Model):
    CHOICES_type = (('A', 'A'), ('CNAME', 'CNAME'), ('AAAA', 'AAAA'), ('MX', 'MX'), ('NS', 'NS'), ('PTR', 'PTR'), ('TXT', 'TXT'))
    name = models.CharField(max_length=40, validators=[val_domain], blank=True, null=True)
    domain = models.ForeignKey('Domain')
    host = models.ForeignKey('Host', blank=True, null=True)
    type = models.CharField(max_length=6, choices=CHOICES_type)
    address = models.CharField(max_length=40, blank=True, null=True)
    ttl = models.IntegerField(default=600)
    owner = models.ForeignKey(User)
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.desc()

    def desc(self):
        a = self.get_data()
        if a:
            return a['name'] + u' ' + a['type'] + u' ' + a['address']
        return '(nincs)'

    def save(self, *args, **kwargs):
        self.full_clean()
        super(Record, self).save(*args, **kwargs)

    def clean(self):
x committed
221
        if self.name and self.name.endswith(u'.'):
Bach Dániel committed
222
            raise ValidationError(u'a domain nem végződhet pontra')
223

Bach Dániel committed
224
        if self.host and self.type in ['CNAME', 'A', 'AAAA']:
225 226 227 228 229 230
            if self.type == 'CNAME':
                if not self.name or self.address:
                    raise ValidationError(u'CNAME rekordnal csak a name legyen kitoltve, ha van host beallitva')
            elif self.name or self.address:
                raise ValidationError(u'A, AAAA rekord eseten nem szabad megadni name-t, address-t, ha tarsitva van host')
        else:
Bach Dániel committed
231 232
            if not self.address:
                raise ValidationError(u'address hianyzik')
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

            if self.type == 'A':
                if not ipv4_re.match(self.address):
                    raise ValidationError(u'ez nem ipcim, ez nudli!')
            elif self.type in ['CNAME', 'NS', 'PTR', 'TXT']:
                if not domain_re.match(self.address):
                    raise ValidationError(u'ez nem domain, ez nudli!')
            elif self.type == 'AAAA':
                if not is_valid_ipv6_address(self.address):
                    raise ValidationError(u'ez nem ipv6cim, ez nudli!')
            elif self.type == 'MX':
                mx = self.address.split(':', 1)
                if not (len(mx) == 2 and mx[0].isdigit() and domain_re.match(mx[1])):
                    raise ValidationError(u'prioritas:hostname')
            else:
                raise ValidationError(u'ez ismeretlen rekord, ez nudli!')

    def get_data(self):
x committed
251 252
        retval = { 'name': self.name, 'type': self.type, 'ttl': self.ttl, 'address': self.address }
        if self.host and self.type in ['CNAME', 'A', 'AAAA']:
253 254 255 256 257 258 259 260 261 262
            if self.type == 'A':
                retval['address'] = self.host.pub_ipv4 if self.host.pub_ipv4 and not self.host.shared_ip else self.host.ipv4
                retval['name'] = self.host.get_fqdn()
            elif self.type == 'AAAA':
                if not self.host.ipv6:
                    return None
                retval['address'] = self.host.ipv6
                retval['name'] = self.host.get_fqdn()
            elif self.type == 'CNAME':
                retval['address'] = self.host.get_fqdn()
Bach Dániel committed
263 264 265 266 267
        else:
            if not self.name:
                retval['name'] = unicode(self.domain)
            else:
                retval['name'] = self.name + u'.' + unicode(self.domain)
268 269 270 271 272 273
        if not (retval['address'] and retval['name']):
            return None
        return retval