Skip to content
Snippets Groups Projects
Commit db19f489 authored by Tomáš Čejka's avatar Tomáš Čejka
Browse files

model: add Rule class and relation with it and Route

Some fields were moved from Route into Rule.
parent b28ef8c8
Branches
Tags
No related merge requests found
......@@ -18,7 +18,7 @@
#
from django.contrib import admin
from flowspec.models import MatchPort, MatchDscp, MatchProtocol, FragmentType, ThenAction, Route
from flowspec.models import MatchPort, MatchDscp, MatchProtocol, FragmentType, ThenAction, Route, Rule
from accounts.models import UserProfile
from utils import proxy as PR
from tasks import *
......@@ -29,19 +29,25 @@ from flowspec.forms import *
from longerusername.forms import UserCreationForm, UserChangeForm
class RuleAdmin(admin.ModelAdmin):
form = RuleForm
class RouteAdmin(admin.ModelAdmin):
form = RouteForm
actions = ['deactivate']
search_fields = ['destination', 'name', 'applier__username']
search_fields = ['destination', 'name', 'applier_username']
def deactivate(self, request, queryset):
queryset = queryset.filter(status='ACTIVE')
queryset = queryset.filter(rule__status='ACTIVE')
response = batch_delete.delay(queryset, reason="ADMININACTIVE")
self.message_user(request, "Added request %s to job que. Check in a while for result" % response)
deactivate.short_description = "Remove selected routes from network"
def save_model(self, request, obj, form, change):
obj.status = "PENDING"
rule = Rule()
rule.save()
obj.rule = rule
obj.rule.status = "PENDING"
obj.save()
if change:
obj.commit_edit()
......@@ -51,14 +57,11 @@ class RouteAdmin(admin.ModelAdmin):
def has_delete_permission(self, request, obj=None):
return False
list_display = ('name', 'status', 'applier_username', 'applier_peers', 'get_match', 'get_then', 'response', "expires", "comments")
list_display = ('name', 'status', 'applier_username', 'applier_peers', 'get_match', 'get_then', 'response', "comments")
fieldsets = [
(None, {'fields': ['name', 'applier']}),
("Match", {'fields': ['source', 'sourceport', 'destination', 'destinationport', 'port']}),
('Advanced Match Statements', {'fields': ['dscp', 'fragmenttype', 'icmpcode', 'icmptype', 'packetlength', 'protocol', 'tcpflag'], 'classes': ['collapse']}),
("Then", {'fields': ['then']}),
("Expires", {'fields': ['expires']}),
(None, {'fields': ['comments', ]}),
]
......
......@@ -86,12 +86,9 @@ class UserProfileForm(forms.ModelForm):
model = UserProfile
class RouteForm(forms.ModelForm):
sourceport = PortRangeForm()
destinationport = PortRangeForm()
port = PortRangeForm()
class RuleForm(forms.ModelForm):
class Meta:
model = Route
model = Rule
def clean_applier(self):
applier = self.cleaned_data['applier']
......@@ -100,31 +97,11 @@ class RouteForm(forms.ModelForm):
else:
raise forms.ValidationError('This field is required.')
def clean_source(self):
# run validator which is used by rest framework too
source = self.cleaned_data['source']
res = clean_source(
User.objects.get(pk=self.data['applier']),
source
)
if res != source:
raise forms.ValidationError(res)
else:
return res
def clean_destination(self):
destination = self.cleaned_data.get('destination')
res = clean_destination(
User.objects.get(pk=self.data['applier']),
destination
)
if destination != res:
raise forms.ValidationError(res)
else:
return res
def clean_expires(self):
date = self.cleaned_data['expires']
if not date:
raise forms.ValidationError('This field is required.')
res = clean_expires(date)
if date != res:
raise forms.ValidationError(res)
......@@ -143,8 +120,72 @@ class RouteForm(forms.ModelForm):
peers = Peer.objects.all()
else:
peers = user.userprofile.peers.all()
existing_routes = self.routes.all()
#existing_routes = existing_routes.filter(rule__applier__userprofile__peers__in=peers)
name = self.cleaned_data.get('name', None)
protocols = self.cleaned_data.get('protocol', None)
source = self.cleaned_data.get('source', None)
sourceports = self.cleaned_data.get('sourceport', None)
port = self.cleaned_data.get('port', None)
destination = self.cleaned_data.get('destination', None)
destinationports = self.cleaned_data.get('destinationport', None)
#user = self.cleaned_data.get('applier', None)
for route in existing_routes:
if name != route.name:
existing_url = reverse('edit-route', args=[route.name])
if IPNetwork(destination) in IPNetwork(route.destination) or IPNetwork(route.destination) in IPNetwork(destination):
raise forms.ValidationError('Found an exact %s rule, %s with destination prefix %s<br>To avoid overlapping try editing rule <a href=\'%s\'>%s</a>' % (route.status, route.name, route.destination, existing_url, route.name))
return self.cleaned_data
class RouteForm(forms.ModelForm):
sourceport = PortRangeForm()
destinationport = PortRangeForm()
port = PortRangeForm()
class Meta:
model = Route
def clean_source(self):
# run validator which is used by rest framework too
source = self.cleaned_data['source']
#res = clean_source(
# User.objects.get(pk=self.data['applier']),
# source
#)
#if res != source:
# raise forms.ValidationError(res)
#else:
# return res
return source
def clean_destination(self):
destination = self.cleaned_data.get('destination')
#res = clean_destination(
# User.objects.get(pk=self.data['applier']),
# destination
#)
#if destination != res:
# raise forms.ValidationError(res)
#else:
# return res
return destination
def clean(self):
if self.errors:
raise forms.ValidationError(_('Errors in form. Please review and fix them: %s' % ", ".join(self.errors)))
error = clean_route_form(self.cleaned_data)
if error:
raise forms.ValidationError(error)
## check if same rule exists with other name
#user = self.cleaned_data['applier']
#if user.is_superuser:
# peers = Peer.objects.all()
#else:
# peers = user.userprofile.peers.all()
existing_routes = Route.objects.all()
existing_routes = existing_routes.filter(applier__userprofile__peers__in=peers)
#existing_routes = existing_routes.filter(rule__applier__userprofile__peers__in=peers)
name = self.cleaned_data.get('name', None)
protocols = self.cleaned_data.get('protocol', None)
source = self.cleaned_data.get('source', None)
......@@ -152,7 +193,7 @@ class RouteForm(forms.ModelForm):
port = self.cleaned_data.get('port', None)
destination = self.cleaned_data.get('destination', None)
destinationports = self.cleaned_data.get('destinationport', None)
user = self.cleaned_data.get('applier', None)
#user = self.cleaned_data.get('applier', None)
if source:
source = IPNetwork(source).compressed
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Rule'
db.create_table(u'flowspec_rule', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.SlugField')(max_length=128)),
('applier', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
('filed', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, auto_now_add=True, blank=True)),
('last_updated', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, auto_now=True, blank=True)),
('comments', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('requesters_address', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
('expires', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2018, 7, 10, 0, 0))),
('status', self.gf('django.db.models.fields.CharField')(default='INACTIVE', max_length=20, null=True, blank=True)),
))
db.send_create_signal('flowspec', ['Rule'])
# Adding M2M table for field then on 'Rule'
db.create_table(u'flowspec_rule_then', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('rule', models.ForeignKey(orm['flowspec.rule'], null=False)),
('thenaction', models.ForeignKey(orm['flowspec.thenaction'], null=False))
))
db.create_unique(u'flowspec_rule_then', ['rule_id', 'thenaction_id'])
# Deleting field 'Route.status'
db.delete_column(u'route', 'status')
# Deleting field 'Route.last_updated'
db.delete_column(u'route', 'last_updated')
# Deleting field 'Route.requesters_address'
db.delete_column(u'route', 'requesters_address')
# Deleting field 'Route.expires'
db.delete_column(u'route', 'expires')
# Deleting field 'Route.filed'
db.delete_column(u'route', 'filed')
# Deleting field 'Route.applier'
db.delete_column(u'route', 'applier_id')
# Adding field 'Route.rule'
db.add_column(u'route', 'rule',
self.gf('django.db.models.fields.related.ForeignKey')(related_name='routes', null=True, to=orm['flowspec.Rule']),
keep_default=False)
# Removing M2M table for field then on 'Route'
db.delete_table('route_then')
# Changing field 'Route.destinationport'
db.alter_column(u'route', 'destinationport', self.gf('django.db.models.fields.CharField')(max_length=65535, null=True))
# Changing field 'Route.sourceport'
db.alter_column(u'route', 'sourceport', self.gf('django.db.models.fields.CharField')(max_length=65535, null=True))
# Changing field 'Route.port'
db.alter_column(u'route', 'port', self.gf('django.db.models.fields.CharField')(max_length=65535, null=True))
def backwards(self, orm):
# Deleting model 'Rule'
db.delete_table(u'flowspec_rule')
# Removing M2M table for field then on 'Rule'
db.delete_table('flowspec_rule_then')
# Adding field 'Route.status'
db.add_column(u'route', 'status',
self.gf('django.db.models.fields.CharField')(default='PENDING', max_length=20, null=True, blank=True),
keep_default=False)
# User chose to not deal with backwards NULL issues for 'Route.last_updated'
raise RuntimeError("Cannot reverse this migration. 'Route.last_updated' and its values cannot be restored.")
# Adding field 'Route.requesters_address'
db.add_column(u'route', 'requesters_address',
self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
keep_default=False)
# Adding field 'Route.expires'
db.add_column(u'route', 'expires',
self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2017, 2, 8, 0, 0)),
keep_default=False)
# User chose to not deal with backwards NULL issues for 'Route.filed'
raise RuntimeError("Cannot reverse this migration. 'Route.filed' and its values cannot be restored.")
# Adding field 'Route.applier'
db.add_column(u'route', 'applier',
self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True),
keep_default=False)
# Deleting field 'Route.rule'
db.delete_column(u'route', 'rule_id')
# Adding M2M table for field then on 'Route'
db.create_table(u'route_then', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('route', models.ForeignKey(orm['flowspec.route'], null=False)),
('thenaction', models.ForeignKey(orm['flowspec.thenaction'], null=False))
))
db.create_unique(u'route_then', ['route_id', 'thenaction_id'])
# Changing field 'Route.destinationport'
db.alter_column(u'route', 'destinationport', self.gf('django.db.models.fields.CharField')(max_length=50, null=True))
# Changing field 'Route.sourceport'
db.alter_column(u'route', 'sourceport', self.gf('django.db.models.fields.CharField')(max_length=50, null=True))
# Changing field 'Route.port'
db.alter_column(u'route', 'port', self.gf('django.db.models.fields.CharField')(max_length=50, null=True))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'flowspec.fragmenttype': {
'Meta': {'object_name': 'FragmentType'},
'fragmenttype': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'flowspec.matchdscp': {
'Meta': {'object_name': 'MatchDscp', 'db_table': "u'match_dscp'"},
'dscp': ('django.db.models.fields.CharField', [], {'max_length': '24'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'flowspec.matchport': {
'Meta': {'object_name': 'MatchPort', 'db_table': "u'match_port'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'port': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '24'})
},
'flowspec.matchprotocol': {
'Meta': {'object_name': 'MatchProtocol', 'db_table': "u'match_protocol'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '24'})
},
'flowspec.route': {
'Meta': {'object_name': 'Route', 'db_table': "u'route'"},
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'destination': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'destinationport': ('django.db.models.fields.CharField', [], {'max_length': '65535', 'null': 'True', 'blank': 'True'}),
'dscp': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flowspec.MatchDscp']", 'null': 'True', 'blank': 'True'}),
'fragmenttype': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flowspec.FragmentType']", 'null': 'True', 'blank': 'True'}),
'icmpcode': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'icmptype': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.SlugField', [], {'max_length': '128'}),
'packetlength': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'port': ('django.db.models.fields.CharField', [], {'max_length': '65535', 'null': 'True', 'blank': 'True'}),
'protocol': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flowspec.MatchProtocol']", 'null': 'True', 'blank': 'True'}),
'response': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}),
'rule': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'routes'", 'null': 'True', 'to': "orm['flowspec.Rule']"}),
'source': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'sourceport': ('django.db.models.fields.CharField', [], {'max_length': '65535', 'null': 'True', 'blank': 'True'}),
'tcpflag': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'})
},
'flowspec.rule': {
'Meta': {'object_name': 'Rule'},
'applier': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'expires': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2018, 7, 10, 0, 0)'}),
'filed': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.SlugField', [], {'max_length': '128'}),
'requesters_address': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'INACTIVE'", 'max_length': '20', 'null': 'True', 'blank': 'True'}),
'then': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['flowspec.ThenAction']", 'symmetrical': 'False'})
},
'flowspec.thenaction': {
'Meta': {'ordering': "['action', 'action_value']", 'unique_together': "(('action', 'action_value'),)", 'object_name': 'ThenAction', 'db_table': "u'then_action'"},
'action': ('django.db.models.fields.CharField', [], {'max_length': '60'}),
'action_value': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['flowspec']
\ No newline at end of file
......@@ -22,7 +22,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse, NoReverseMatch
from flowspec.helpers import send_new_mail, get_peer_techc_mails
from utils import proxy as PR
......@@ -135,31 +135,22 @@ class ThenAction(models.Model):
unique_together = ("action", "action_value")
class Route(models.Model):
class Rule(models.Model):
name = models.SlugField(max_length=128, verbose_name=_("Name"))
applier = models.ForeignKey(User, blank=True, null=True)
source = models.CharField(max_length=32, help_text=_("Network address. Use address/CIDR notation"), verbose_name=_("Source Address"))
sourceport = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Source Port"))
destination = models.CharField(max_length=32, help_text=_("Network address. Use address/CIDR notation"), verbose_name=_("Destination Address"))
destinationport = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Destination Port"))
port = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Port"))
dscp = models.ManyToManyField(MatchDscp, blank=True, null=True, verbose_name="DSCP")
fragmenttype = models.ManyToManyField(FragmentType, blank=True, null=True, verbose_name="Fragment Type")
icmpcode = models.CharField(max_length=32, blank=True, null=True, verbose_name="ICMP Code")
icmptype = models.CharField(max_length=32, blank=True, null=True, verbose_name="ICMP Type")
packetlength = models.IntegerField(blank=True, null=True, verbose_name="Packet Length")
protocol = models.ManyToManyField(MatchProtocol, blank=True, null=True, verbose_name=_("Protocol"))
tcpflag = models.CharField(max_length=128, blank=True, null=True, verbose_name="TCP flag")
then = models.ManyToManyField(ThenAction, verbose_name=_("Then"))
filed = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=20, choices=ROUTE_STATES, blank=True, null=True, verbose_name=_("Status"), default="PENDING")
# is_online = models.BooleanField(default=False)
# is_active = models.BooleanField(default=False)
expires = models.DateField(default=days_offset, verbose_name=_("Expires"))
response = models.CharField(max_length=512, blank=True, null=True, verbose_name=_("Response"))
filed = models.DateTimeField(auto_now_add=True, default=datetime.datetime.now, null=False)
last_updated = models.DateTimeField(auto_now=True, default=datetime.datetime.now, null=False)
comments = models.TextField(null=True, blank=True, verbose_name=_("Comments"))
requesters_address = models.CharField(max_length=255, blank=True, null=True)
expires = models.DateField(default=days_offset, verbose_name=_("Expires"))
status = models.CharField(max_length=20, choices=ROUTE_STATES, blank=True, null=True, verbose_name=_("Status"), default="INACTIVE")
class Meta:
db_table = u'flowspec_rule'
verbose_name = "Rule"
verbose_name_plural = "Rules"
@property
def applier_username(self):
......@@ -168,35 +159,32 @@ class Route(models.Model):
else:
return None
def __unicode__(self):
return self.name
class Meta:
db_table = u'route'
verbose_name = "Rule"
verbose_name_plural = "Rules"
def save(self, *args, **kwargs):
if not self.pk:
hash = id_gen()
self.name = "%s_%s" % (self.name, hash)
super(Route, self).save(*args, **kwargs) # Call the "real" save() method.
super(Rule, self).save(*args, **kwargs) # Call the "real" save() method.
def clean(self, *args, **kwargs):
from django.core.exceptions import ValidationError
if self.destination:
try:
address = IPNetwork(self.destination)
self.destination = address.exploded
except Exception:
raise ValidationError(_('Invalid network address format at Destination Field'))
if self.source:
try:
address = IPNetwork(self.source)
self.source = address.exploded
except Exception:
raise ValidationError(_('Invalid network address format at Source Field'))
def _send_mail(self, *args, **kwargs):
args = kwargs.get("args")
fqdn = Site.objects.get_current().domain
try:
admin_url = 'https://%s%s' % (fqdn, reverse(args.get("url_path"), kwargs={args.get("url_id"): self.name}))
except NoReverseMatch:
admin_url = "Unknown"
args["url"] = admin_url
mail_body = render_to_string('rule_action.txt', args)
user_mail = '%s' % self.applier.email
user_mail = user_mail.split(';')
send_new_mail(
args.get("subject"),
mail_body,
settings.SERVER_EMAIL, user_mail,
get_peer_techc_mails(self.applier, args.get("peer"))
)
return mail_body
def commit_add(self, *args, **kwargs):
peers = self.applier.get_profile().peers.all()
username = None
......@@ -205,9 +193,10 @@ class Route(models.Model):
break
for network in peer.networks.all():
net = IPNetwork(network)
if IPNetwork(self.destination) in net:
username = peer
break
for route in self.routes.all():
if IPNetwork(route.destination) in net:
username = peer
break
if username:
peer = username.peer_tag
else:
......@@ -215,29 +204,17 @@ class Route(models.Model):
send_message("[%s] Adding rule %s. Please wait..." % (self.applier.username, self.name), peer)
response = add.delay(self)
logger.info('Got add job id: %s' % response)
fqdn = Site.objects.get_current().domain
admin_url = 'https://%s%s' % (
fqdn,
reverse('edit-route', kwargs={'route_slug': self.name})
)
mail_body = render_to_string(
'rule_action.txt',
{
'route': self,
mail_body = self._send_mail(args={
'url_path': 'edit-route',
'url_id': 'route_slug',
'rule': self,
'routes': self.routes.all(),
'address': self.requesters_address,
'action': 'creation',
'url': admin_url,
'peer': username
}
)
user_mail = '%s' % self.applier.email
user_mail = user_mail.split(';')
send_new_mail(
settings.EMAIL_SUBJECT_PREFIX + 'Rule %s creation request submitted by %s' % (self.name, self.applier.username),
mail_body,
settings.SERVER_EMAIL, user_mail,
get_peer_techc_mails(self.applier, username)
)
'peer': username,
'subject': settings.EMAIL_SUBJECT_PREFIX + 'Rule %s creation request submitted by %s' % (self.name, self.applier.username),
})
d = {
'clientip': '%s' % self.requesters_address,
'user': self.applier.username
......@@ -252,9 +229,10 @@ class Route(models.Model):
break
for network in peer.networks.all():
net = IPNetwork(network)
if IPNetwork(self.destination) in net:
username = peer
break
for route in self.routes.all():
if IPNetwork(route.destination) in net:
username = peer
break
if username:
peer = username.peer_tag
else:
......@@ -268,31 +246,17 @@ class Route(models.Model):
)
response = edit.delay(self)
logger.info('Got edit job id: %s' % response)
fqdn = Site.objects.get_current().domain
admin_url = 'https://%s%s' % (
fqdn,
reverse(
'edit-route',
kwargs={'route_slug': self.name}
)
)
mail_body = render_to_string(
'rule_action.txt',
{
'route': self,
mail_body = self._send_mail(args={
'url_path': 'edit-route',
'url_id': 'route_slug',
'rule': self,
'routes': self.routes.all(),
'address': self.requesters_address,
'action': 'edit',
'url': admin_url,
'peer': username
}
)
user_mail = '%s' % self.applier.email
user_mail = user_mail.split(';')
send_new_mail(
settings.EMAIL_SUBJECT_PREFIX + 'Rule %s edit request submitted by %s' % (self.name, self.applier.username),
mail_body, settings.SERVER_EMAIL, user_mail,
get_peer_techc_mails(self.applier, username)
)
'peer': username,
'subject': settings.EMAIL_SUBJECT_PREFIX + 'Rule %s edit request submitted by %s' % (self.name, self.applier.username),
})
d = {
'clientip': self.requesters_address,
'user': self.applier.username
......@@ -312,9 +276,10 @@ class Route(models.Model):
break
for network in peer.networks.all():
net = IPNetwork(network)
if IPNetwork(self.destination) in net:
username = peer
break
for route in self.routes.all():
if IPNetwork(route.destination) in net:
username = peer
break
if username:
peer = username.peer_tag
else:
......@@ -328,45 +293,92 @@ class Route(models.Model):
)
response = delete.delay(self, reason=reason)
logger.info('Got delete job id: %s' % response)
fqdn = Site.objects.get_current().domain
admin_url = 'https://%s%s' % (
fqdn,
reverse(
'edit-route',
kwargs={'route_slug': self.name}
)
)
mail_body = render_to_string(
'rule_action.txt',
{
'route': self,
mail_body = self._send_mail(args={
'url_path': 'edit-route',
'url_id': 'route_slug',
'rule': self,
'routes': self.routes.all(),
'address': self.requesters_address,
'action': 'removal',
'url': admin_url,
'peer': username
}
)
user_mail = '%s' % self.applier.email
user_mail = user_mail.split(';')
send_new_mail(
settings.EMAIL_SUBJECT_PREFIX + 'Rule %s removal request submitted by %s' % (self.name, self.applier.username),
mail_body,
settings.SERVER_EMAIL,
user_mail,
get_peer_techc_mails(self.applier, username)
)
'peer': username,
'subject': settings.EMAIL_SUBJECT_PREFIX + 'Rule %s removal request submitted by %s' % (self.name, self.applier.username),
})
d = {
'clientip': self.requesters_address,
'user': self.applier.username
}
logger.info(mail_body, extra=d)
class Route(models.Model):
name = models.SlugField(max_length=128, verbose_name=_("Name"))
rule = models.ForeignKey(Rule, related_name='routes', null=True)
source = models.CharField(max_length=32, help_text=_("Network address. Use address/CIDR notation"), verbose_name=_("Source Address"))
sourceport = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Source Port"))
destination = models.CharField(max_length=32, help_text=_("Network address. Use address/CIDR notation"), verbose_name=_("Destination Address"))
destinationport = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Destination Port"))
port = models.CharField(max_length=65535, blank=True, null=True, verbose_name=_("Port"))
dscp = models.ManyToManyField(MatchDscp, blank=True, null=True, verbose_name="DSCP")
fragmenttype = models.ManyToManyField(FragmentType, blank=True, null=True, verbose_name="Fragment Type")
icmpcode = models.CharField(max_length=32, blank=True, null=True, verbose_name="ICMP Code")
icmptype = models.CharField(max_length=32, blank=True, null=True, verbose_name="ICMP Type")
packetlength = models.IntegerField(blank=True, null=True, verbose_name="Packet Length")
protocol = models.ManyToManyField(MatchProtocol, blank=True, null=True, verbose_name=_("Protocol"))
tcpflag = models.CharField(max_length=128, blank=True, null=True, verbose_name="TCP flag")
# is_online = models.BooleanField(default=False)
# is_active = models.BooleanField(default=False)
response = models.CharField(max_length=512, blank=True, null=True, verbose_name=_("Response"))
comments = models.TextField(null=True, blank=True, verbose_name=_("Comments"))
@property
def applier_username(self):
if self.rule and self.rule.applier:
return self.rule.applier.username
else:
return None
def __unicode__(self):
return self.name
class Meta:
db_table = u'route'
verbose_name = "Route"
verbose_name_plural = "Routes"
def save(self, *args, **kwargs):
if not self.pk:
hash = id_gen()
self.name = "%s_%s" % (self.name, hash)
super(Route, self).save(*args, **kwargs) # Call the "real" save() method.
def clean(self, *args, **kwargs):
from django.core.exceptions import ValidationError
if self.destination:
try:
address = IPNetwork(self.destination)
self.destination = address.exploded
except Exception:
raise ValidationError(_('Invalid network address format at Destination Field'))
if self.source:
try:
address = IPNetwork(self.source)
self.source = address.exploded
except Exception:
raise ValidationError(_('Invalid network address format at Source Field'))
def has_expired(self):
today = datetime.date.today()
if today > self.expires:
return True
return False
def status(self):
if self.rule:
return self.rule.status
else:
return ROUTE_STATES["INACTIVE"]
def check_sync(self):
if not self.is_synced():
self.status = "OUTOFSYNC"
......
# -*- coding: utf-8 -*- vim:fileencoding=utf-8:
# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab
from rest_framework import serializers
from flowspec.models import (
Route,
Rule,
MatchPort,
ThenAction,
FragmentType,
......@@ -14,9 +18,52 @@ from flowspec.validators import (
)
class RouteSerializer(serializers.HyperlinkedModelSerializer):
class PeerSerializer(serializers.HyperlinkedModelSerializer):
pass
class RuleSerializer(serializers.HyperlinkedModelSerializer):
applier = serializers.CharField(source='applier_username', read_only=True)
def validate_expires(self, attrs, source):
print("validate expires ")
value = attrs[source]
if not value:
raise serializers.ValidationError('This field is required')
res = clean_expires(value)
if res != value:
raise serializers.ValidationError(res)
return attrs
def validate_then(self, attrs, source):
if not source:
raise serializers.ValidationError('This field is required')
return attrs
def validate(self, data):
user = self.context.get('request').user
return data
class Meta:
model = Rule
fields = (
'name',
'id',
'comments',
'applier',
'then',
'routes',
'filed',
'last_updated',
'expires',
'status',
'requesters_address',
'url'
)
read_only_fields = ('requesters_address', )
class RouteSerializer(serializers.HyperlinkedModelSerializer):
def validate(self, data):
user = self.context.get('request').user
# validate source
......@@ -37,14 +84,6 @@ class RouteSerializer(serializers.HyperlinkedModelSerializer):
if res != destination:
raise serializers.ValidationError(res)
# validate expires
expires = data.get('expires')
res = clean_expires(
expires
)
if res != expires:
raise serializers.ValidationError(res)
# check if rule already exists with different name
fields = {
'source': data.get('source'),
......@@ -60,8 +99,7 @@ class RouteSerializer(serializers.HyperlinkedModelSerializer):
fields = (
'name',
'id',
'comments',
'applier',
'rule',
'source',
'sourceport',
'destination',
......@@ -73,16 +111,10 @@ class RouteSerializer(serializers.HyperlinkedModelSerializer):
'packetlength',
'protocol',
'tcpflag',
'then',
'filed',
'last_updated',
'status',
'expires',
'response',
'comments',
'requesters_address',
'url',
)
read_only_fields = ('status', 'expires', 'requesters_address', 'response')
read_only_fields = ('response', 'id')
class PortSerializer(serializers.HyperlinkedModelSerializer):
......
......@@ -4,7 +4,7 @@ from django.conf import settings
from django.core.mail import send_mail
from django.utils.translation import ugettext as _
from peers.models import PeerRange, Peer
from flowspec.models import Route
from flowspec.models import Route, Rule
from django.core.urlresolvers import reverse
......@@ -149,5 +149,5 @@ def check_if_rule_exists(fields):
destination=IPNetwork(fields.get('destination')).compressed,
)
for route in routes:
return _('Rule exists with id %s and status %s. Please edit it.' % (route.id, route.status))
return _('Rule exists with id {id} and status {status}. Please edit it.'.format(id=route.id, status=route.status))
return False
from django.shortcuts import get_object_or_404
from django.conf import settings
from django.http import HttpResponse
from rest_framework.exceptions import PermissionDenied
import json
from rest_framework import viewsets
from flowspec.models import (
Route,
Rule,
User,
MatchPort,
ThenAction,
FragmentType,
MatchProtocol
)
from peers.models import PeerRange
from flowspec.serializers import (
RuleSerializer,
RouteSerializer,
PortSerializer,
PeerSerializer,
ThenActionSerializer,
FragmentTypeSerializer,
MatchProtocolSerializer,
......@@ -21,6 +28,71 @@ from flowspec.serializers import (
from rest_framework.response import Response
class PeerViewSet(viewsets.ViewSet):
queryset = User.objects.all()
def get_queryset(self):
if self.request.user.is_authenticated: # and not self.request.user.is_anonymous:
pr = PeerRange.objects.filter(peer__user_profile__peers=self.request.user)
return [str(net) for net in pr]
else:
raise PermissionDenied('User is not Authenticated')
def list(self, request):
return HttpResponse(json.dumps({"networks": self.get_queryset()}), content_type="application/json")
class RuleViewSet(viewsets.ModelViewSet):
queryset = Rule.objects.all()
serializer_class = RuleSerializer
def get_queryset(self):
if settings.DEBUG:
if self.request.user.is_anonymous():
return Rule.objects.all()
elif self.request.user.is_authenticated():
return Rule.objects.filter(applier=self.request.user)
else:
raise PermissionDenied('User is not Authenticated')
if self.request.user.is_superuser:
return Rule.objects.all()
elif self.request.user.is_authenticated and not self.request.user.is_anonymous:
return Rule.objects.filter(applier=self.request.user)
def list(self, request):
serializer = RuleSerializer(self.get_queryset(), many=True, context={'request': request})
return Response(serializer.data)
def create(self, request):
serializer = RuleSerializer(context={'request': request})
return super(RuleViewSet, self).create(request)
def retrieve(self, request, pk=None):
rule = get_object_or_404(self.get_queryset(), pk=pk)
serializer = RuleSerializer(rule)
return Response(serializer.data)
def pre_save(self, obj):
# DEBUG
if settings.DEBUG:
if self.request.user.is_anonymous():
from django.contrib.auth.models import User
obj.applier = User.objects.all()[0]
elif self.request.user.is_authenticated():
obj.applier = self.request.user
else:
raise PermissionDenied('User is not Authenticated')
else:
obj.applier = self.request.user
def post_save(self, obj, created):
if created:
obj.commit_add()
else:
if obj.status not in ['EXPIRED', 'INACTIVE', 'ADMININACTIVE']:
obj.commit_edit()
def pre_delete(self, obj):
obj.commit_delete()
class RouteViewSet(viewsets.ModelViewSet):
queryset = Route.objects.all()
......@@ -31,7 +103,7 @@ class RouteViewSet(viewsets.ModelViewSet):
if self.request.user.is_anonymous():
return Route.objects.all()
elif self.request.user.is_authenticated():
return Route.objects.filter(applier=self.request.user)
return Route.objects.filter(rule__applier=self.request.user)
else:
raise PermissionDenied('User is not Authenticated')
......@@ -66,15 +138,15 @@ class RouteViewSet(viewsets.ModelViewSet):
else:
obj.applier = self.request.user
def post_save(self, obj, created):
if created:
obj.commit_add()
else:
if obj.status not in ['EXPIRED', 'INACTIVE', 'ADMININACTIVE']:
obj.commit_edit()
#def post_save(self, obj, created):
# if created:
# obj.commit_add()
# else:
# if obj.status not in ['EXPIRED', 'INACTIVE', 'ADMININACTIVE']:
# obj.commit_edit()
def pre_delete(self, obj):
obj.commit_delete()
#def pre_delete(self, obj):
# obj.commit_delete()
class PortViewSet(viewsets.ModelViewSet):
......
......@@ -4,8 +4,10 @@ from django.contrib import admin
from rest_framework import routers
from graphs import urls as graphs_urls
from flowspec.viewsets import (
RuleViewSet,
RouteViewSet,
PortViewSet,
PeerViewSet,
ThenActionViewSet,
FragmentTypeViewSet,
MatchProtocolViewSet,
......@@ -15,8 +17,10 @@ admin.autodiscover()
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'rules', RuleViewSet, base_name='rule')
router.register(r'routes', RouteViewSet, base_name='route')
router.register(r'ports', PortViewSet)
router.register(r'peers', PeerViewSet)
router.register(r'thenactions', ThenActionViewSet)
router.register(r'fragmentypes', FragmentTypeViewSet)
router.register(r'matchprotocol', MatchProtocolViewSet)
......
{% load tofqdn %}{% ifequal action 'expires' %}Rule {{route.name}} expires {% ifequal expiration_days 0 %}today{% else%}in {{expiration_days}} day{{ expiration_days|pluralize }}{% endifequal %}{% else %}A new rule {{action}} job has spawned
{% load tofqdn %}{% ifequal action 'expires' %}Rule {{rule.name}} expires {% ifequal expiration_days 0 %}today{% else%}in {{expiration_days}} day{{ expiration_days|pluralize }}{% endifequal %}{% else %}A new rule {{action}} job has spawned
Peer: {{peer.peer_name}}
User {{route.applier.username}} requested the {{action}} of the following rule from address {{address}} {% if address|tofqdn %}({{address|tofqdn}}){% endif %}:
Rule name: {{route.name}}{% endifequal %}
Rule name: {{rule.name}}{% endifequal %}
{% for route in routes %}
Match Statements:
* Source Address: {{route.source}}
* Destination Address: {{route.destination}}
......@@ -14,13 +15,15 @@ Match Statements:
* Destination Ports: {% if route.port %}same as ports{% else %}{% if route.destinationport %}{{ route.destinationport }}{% else %}any{% endif %}{% endif %}
* Fragment Types: {% if route.fragmenttype.all %}{% for fragment in route.fragmenttype.all %}{{ fragment }}{% if not forloop.last %}, {% endif %}{% endfor %}{% else %}-{% endif %}
{% endfor %}
Then Actions:
* Action:{% for then in route.then.all %}{{ then }}{% if not forloop.last %}, {% endif %}{% endfor %}
* Action:{% for then in rule.then.all %}{{ then }}{% if not forloop.last %}, {% endif %}{% endfor %}
Comments: {% if route.comments %}{{route.comments}}{% else %}-{% endif %}
Comments: {% if rule.comments %}{{rule.comments}}{% else %}-{% endif %}
Expires: {% ifequal action 'removal' %}Now, removal requested{%else%}{{route.expires}}{% endifequal %}
Expires: {% ifequal action 'removal' %}Now, removal requested{%else%}{{rule.expires}}{% endifequal %}
Rule url: {{url}}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment