Commit 8d049e20 by Bach Dániel

firewall new models: Domain, Record

parent de982c2f
...@@ -11,13 +11,16 @@ class AliasInline(contrib.admin.TabularInline): ...@@ -11,13 +11,16 @@ class AliasInline(contrib.admin.TabularInline):
class RuleInline(contrib.admin.TabularInline): class RuleInline(contrib.admin.TabularInline):
model = Rule model = Rule
class RecordInline(contrib.admin.TabularInline):
model = Record
class HostAdmin(admin.ModelAdmin): class HostAdmin(admin.ModelAdmin):
list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', 'shared_ip', 'owner', 'description', 'reverse', 'groups_l') list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac', 'shared_ip', 'owner', 'description', 'reverse', 'groups_l')
ordering = ('hostname', ) ordering = ('hostname', )
list_filter = ('owner', 'vlan', 'groups') list_filter = ('owner', 'vlan', 'groups')
search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac') search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac')
filter_horizontal = ('groups', ) filter_horizontal = ('groups', )
inlines = (AliasInline, RuleInline) inlines = (RuleInline, RecordInline)
def groups_l(self, instance): def groups_l(self, instance):
retval = [] retval = []
...@@ -72,6 +75,22 @@ class GroupAdmin(admin.ModelAdmin): ...@@ -72,6 +75,22 @@ class GroupAdmin(admin.ModelAdmin):
class FirewallAdmin(admin.ModelAdmin): class FirewallAdmin(admin.ModelAdmin):
inlines = (RuleInline, ) inlines = (RuleInline, )
class DomainAdmin(admin.ModelAdmin):
list_display = ('name', 'owner')
class RecordAdmin(admin.ModelAdmin):
list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner')
def address_(self, instance):
a = instance.get_data()
if(a):
return a['address']
def name_(self, instance):
a = instance.get_data()
if(a):
return a['name']
admin.site.register(Host, HostAdmin) admin.site.register(Host, HostAdmin)
admin.site.register(Vlan, VlanAdmin) admin.site.register(Vlan, VlanAdmin)
admin.site.register(Rule, RuleAdmin) admin.site.register(Rule, RuleAdmin)
...@@ -79,3 +98,6 @@ admin.site.register(Alias, AliasAdmin) ...@@ -79,3 +98,6 @@ admin.site.register(Alias, AliasAdmin)
admin.site.register(Group, GroupAdmin) admin.site.register(Group, GroupAdmin)
admin.site.register(VlanGroup) admin.site.register(VlanGroup)
admin.site.register(Firewall, FirewallAdmin) admin.site.register(Firewall, FirewallAdmin)
admin.site.register(Domain, DomainAdmin)
admin.site.register(Record, RecordAdmin)
...@@ -9,6 +9,7 @@ mac_re = re.compile(r'^([0-9a-fA-F]{2}([:-]?|$)){6}$') ...@@ -9,6 +9,7 @@ mac_re = re.compile(r'^([0-9a-fA-F]{2}([:-]?|$)){6}$')
alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$') alfanum_re = re.compile(r'^[A-Za-z0-9_-]+$')
domain_re = re.compile(r'^([A-Za-z0-9_-]\.?)+$') domain_re = re.compile(r'^([A-Za-z0-9_-]\.?)+$')
ipv4_re = re.compile('^[0-9]+\.([0-9]+)\.([0-9]+)\.([0-9]+)$') ipv4_re = re.compile('^[0-9]+\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
reverse_domain_re = re.compile(r'^(%\([abcd]\)d|[a-z0-9.-])+$')
class MACAddressFormField(fields.RegexField): class MACAddressFormField(fields.RegexField):
default_error_messages = { default_error_messages = {
...@@ -41,6 +42,10 @@ def val_domain(value): ...@@ -41,6 +42,10 @@ def val_domain(value):
if not domain_re.search(value): if not domain_re.search(value):
raise ValidationError(u'%s - helytelen domain' % value) raise ValidationError(u'%s - helytelen domain' % value)
def val_reverse_domain(value):
if not reverse_domain_re.search(value):
raise ValidationError(u'%s - reverse domain' % value)
def ipv4_2_ipv6(ipv4): def ipv4_2_ipv6(ipv4):
m = ipv4_re.match(ipv4) m = ipv4_re.match(ipv4)
return "2001:738:2001:4031:%s:%s:%s:0" % (m.group(1), m.group(2), m.group(3)) return "2001:738:2001:4031:%s:%s:%s:0" % (m.group(1), m.group(2), m.group(3))
...@@ -350,38 +350,31 @@ def dns(): ...@@ -350,38 +350,31 @@ def dns():
for i_vlan in vlans: for i_vlan in vlans:
m = regex.search(i_vlan.net4) m = regex.search(i_vlan.net4)
if(i_vlan.name != "DMZ" and i_vlan.name != "PUB"): rev = i_vlan.reverse_domain
DNS.append("Z%s.%s.in-addr.arpa:%s:support.ik.bme.hu::::::%s" % (m.group(2), m.group(1), settings['dns_hostname'], settings['dns_ttl']))
DNS.append("&%s.%s.in-addr.arpa::%s:%s:" % (m.group(2), m.group(1), settings['dns_hostname'], settings['dns_ttl']))
DNS.append("Z%s:%s:support.ik.bme.hu::::::%s" % (i_vlan.domain, settings['dns_hostname'], settings['dns_ttl']))
DNS.append("&%s::%s:%s" % (i_vlan.domain, settings['dns_hostname'], settings['dns_ttl']))
if(i_vlan.name == "WAR"):
DNS.append("Zdns1.%s.%s.%s.in-addr.arpa:%s:support.ik.bme.hu::::::%s" % (m.group(3), m.group(2), m.group(1), settings['dns_hostname'], settings['dns_ttl']))
DNS.append("&dns1.%s.%s.%s.in-addr.arpa::%s:%s::" % (m.group(3), m.group(2), m.group(1), settings['dns_hostname'], settings['dns_ttl']))
for i_host in i_vlan.host_set.all(): for i_host in i_vlan.host_set.all():
ipv4 = ( i_host.pub_ipv4 if i_host.pub_ipv4 and not i_host.shared_ip else i_host.ipv4 ) ipv4 = ( i_host.pub_ipv4 if i_host.pub_ipv4 and not i_host.shared_ip else i_host.ipv4 )
reverse = i_host.reverse if(i_host.reverse and len(i_host.reverse)) else i_host.hostname + u'.' + i_vlan.domain i = ipv4.split('.', 4)
hostname = i_host.get_fqdn() reverse = i_host.reverse if(i_host.reverse and len(i_host.reverse)) else i_host.get_fqdn()
# ipv4 # ipv4
if i_host.ipv4: if i_host.ipv4:
# A record DNS.append("^%s:%s:%s" % ((rev % { 'a': int(i[0]), 'b': int(i[1]), 'c': int(i[2]), 'd': int(i[3]) }), reverse, models.settings['dns_ttl']))
DNS.append("+%s:%s:%s" % (hostname, ipv4, settings['dns_ttl']))
# PTR record 4.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4), reverse, settings['dns_ttl']))
# PTR record 4.dns1.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4, cname=True), reverse, settings['dns_ttl']))
# ipv6 # ipv6
if i_host.ipv6: if i_host.ipv6:
# AAAA record DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6), reverse, models.settings['dns_ttl']))
DNS.append(":%s:28:%s:%s" % (hostname, ipv6_to_octal(i_host.ipv6), settings['dns_ttl']))
# PTR record for r in models.Record.objects.all():
DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6), reverse, settings['dns_ttl'])) d = r.get_data()
if d['type'] == 'A':
# cname DNS.append("+%s:%s:%s" % (d['name'], d['address'], d['ttl']))
for i_alias in i_host.alias_set.all(): elif d['type'] == 'AAAA':
DNS.append("C%s:%s:%s" % (i_alias.alias, hostname, settings['dns_ttl'])) DNS.append(":%s:28:%s:%s" % (d['name'], ipv6_to_octal(d['address']), d['ttl']))
elif d['type'] == 'NS':
DNS.append("&%s::%s:%s" % (d['name'], d['address'], d['ttl']))
elif d['type'] == 'CNAME':
DNS.append("C%s:%s:%s" % (d['name'], d['address'], d['ttl']))
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' % settings['dns_hostname']], shell=False, stdin=subprocess.PIPE) process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' % settings['dns_hostname']], shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS)+"\n") process.communicate("\n".join(DNS)+"\n")
......
...@@ -8,6 +8,8 @@ from firewall.fields import * ...@@ -8,6 +8,8 @@ from firewall.fields import *
from south.modelsinspector import add_introspection_rules from south.modelsinspector import add_introspection_rules
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from cloud.settings import firewall_settings as settings from cloud.settings import firewall_settings as settings
from django.utils.ipv6 import is_valid_ipv6_address
import re
class Rule(models.Model): class Rule(models.Model):
CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan')) CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan'))
...@@ -70,7 +72,8 @@ class Vlan(models.Model): ...@@ -70,7 +72,8 @@ class Vlan(models.Model):
snat_to = models.ManyToManyField('self', symmetrical=False, blank=True, null=True) snat_to = models.ManyToManyField('self', symmetrical=False, blank=True, null=True)
description = models.TextField(blank=True) description = models.TextField(blank=True)
comment = models.TextField(blank=True) comment = models.TextField(blank=True)
domain = models.TextField(blank=True, validators=[val_domain]) domain = models.ForeignKey('Domain')
reverse_domain = models.TextField(validators=[val_reverse_domain])
dhcp_pool = models.TextField(blank=True) dhcp_pool = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, blank=True, null=True) owner = models.ForeignKey(User, blank=True, null=True)
...@@ -143,6 +146,7 @@ class Host(models.Model): ...@@ -143,6 +146,7 @@ class Host(models.Model):
return self.hostname return self.hostname
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
id = self.id
if not self.id and self.ipv6 == "auto": if not self.id and self.ipv6 == "auto":
self.ipv6 = ipv4_2_ipv6(self.ipv4) self.ipv6 = ipv4_2_ipv6(self.ipv4)
if not self.shared_ip and self.pub_ipv4 and Host.objects.exclude(id=self.id).filter(pub_ipv4=self.pub_ipv4): if not self.shared_ip and self.pub_ipv4 and Host.objects.exclude(id=self.id).filter(pub_ipv4=self.pub_ipv4):
...@@ -151,6 +155,10 @@ class Host(models.Model): ...@@ -151,6 +155,10 @@ class Host(models.Model):
raise ValidationError("Egy masik host natolt cimet nem hasznalhatod sajat ipv4-nek") raise ValidationError("Egy masik host natolt cimet nem hasznalhatod sajat ipv4-nek")
self.full_clean() self.full_clean()
super(Host, self).save(*args, **kwargs) super(Host, self).save(*args, **kwargs)
if(id is None):
Record(domain=self.vlan.domain, host=self, type='A', owner=self.owner).save()
if self.ipv6 == "auto":
Record(domain=self.vlan.domain, host=self, type='AAAA', owner=self.owner).save()
def enable_net(self): def enable_net(self):
self.groups.add(Group.objects.get(name="netezhet")) self.groups.add(Group.objects.get(name="netezhet"))
...@@ -179,14 +187,7 @@ class Host(models.Model): ...@@ -179,14 +187,7 @@ class Host(models.Model):
self.rules.filter(owner=self.owner).delete() self.rules.filter(owner=self.owner).delete()
def get_fqdn(self): def get_fqdn(self):
return self.hostname + u'.' + self.vlan.domain return self.hostname + u'.' + unicode(self.vlan.domain)
def clean(self):
# FIXME later: critical race condition
for a in Alias.objects.all():
if self.get_fqdn() == a.alias:
raise ValidationError(_("Host name already used as alias."))
class Firewall(models.Model): class Firewall(models.Model):
...@@ -195,3 +196,92 @@ class Firewall(models.Model): ...@@ -195,3 +196,92 @@ class Firewall(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
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):
if not((not self.name and self.host) or self.name.endswith(u'.' + self.domain.name) or self.name == self.domain.name ):
raise ValidationError(u'nemok')
if self.host and self.type in ['CNAME', 'A', 'AAAA', 'PTR']:
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.type == 'PTR':
if not self.address or self.name:
raise ValidationError(u'PTR 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:
if not (self.name and self.address):
raise ValidationError(u'name v address hianyzik')
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):
retval = { 'name': self.name, 'type': self.type, 'ttl': self.ttl, 'address': self.address }
if self.host:
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()
if not (retval['address'] and retval['name']):
return None
return retval
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment