Merge branch 'master' of https://code.grnet.gr/git/flowspy v0.8.0
authorLeonidas Poulopoulos <leopoul@noc.grnet.gr>
Wed, 15 Feb 2012 10:42:19 +0000 (12:42 +0200)
committerLeonidas Poulopoulos <leopoul@noc.grnet.gr>
Wed, 15 Feb 2012 10:42:19 +0000 (12:42 +0200)
15 files changed:
flowspec/admin.py
flowspec/fixtures/initial_data.json
flowspec/forms.py
flowspec/migrations/0001_initial.py [new file with mode: 0644]
flowspec/migrations/0002_auto__add_matchprotocol__del_field_route_protocol.py [new file with mode: 0644]
flowspec/migrations/__init__.py [new file with mode: 0644]
flowspec/models.py
flowspec/views.py
settings.py.dist
templates/apply.html
templates/rule_add_mail.txt
templates/rule_delete_mail.txt
templates/rule_edit_mail.txt
templates/rule_expiration.txt
utils/proxy.py

index f89064c..e0f12ad 100644 (file)
@@ -74,6 +74,7 @@ class UserProfileAdmin(UserAdmin):
 
 admin.site.unregister(User)
 admin.site.register(MatchPort)
+admin.site.register(MatchProtocol)
 admin.site.register(MatchDscp)
 admin.site.register(ThenAction)
 admin.site.register(Route, RouteAdmin)
index 4895782..ac009ed 100644 (file)
             "action": "rate-limit", 
             "action_value": "100k"
         }
+    },
+    {
+        "pk": 1,
+        "model": "flowspec.matchprotocol",
+        "fields": {
+            "protocol": "icmp"
+        }
+    },
+    {
+        "pk": 2,
+        "model": "flowspec.matchprotocol",
+        "fields": {
+            "protocol": "tcp"
+        }
+    },
+    {
+        "pk": 3,
+        "model": "flowspec.matchprotocol",
+        "fields": {
+            "protocol": "udp"
+        }
     }
+
 ]
\ No newline at end of file
index f5741c6..3d7230f 100644 (file)
@@ -102,6 +102,7 @@ class RouteForm(forms.ModelForm):
         then = self.cleaned_data.get('then', None)
         destination = self.cleaned_data.get('destination', None)
         destinationports = self.cleaned_data.get('destinationport', None)
+        protocols = self.cleaned_data.get('protocol', None)
         user = self.cleaned_data.get('applier', None)
         peer = user.get_profile().peer
         networks = peer.networks.all()
@@ -126,13 +127,21 @@ class RouteForm(forms.ModelForm):
             raise forms.ValidationError('Fill at least a Rule Match Condition')
         if not user.is_superuser and then[0].action not in settings.UI_USER_THEN_ACTIONS:
             raise forms.ValidationError('This action "%s" is not permitted' %(then[0].action))
-        existing_routes = Route.objects.exclude(status='EXPIRED').exclude(status='PENDING').exclude(status='ERROR').exclude(status='ADMININACTIVE')
+        existing_routes = Route.objects.exclude(status='EXPIRED').exclude(status='ERROR').exclude(status='ADMININACTIVE')
         existing_routes = existing_routes.filter(applier__userprofile__peer=peer)
         if source:
             source = IPNetwork(source).compressed
             existing_routes = existing_routes.filter(source=source)
         else:
             existing_routes = existing_routes.filter(source=None)
+        if protocols:
+            route_pk_list=get_matchingprotocol_route_pks(protocols, existing_routes)
+            if route_pk_list:
+                existing_routes = existing_routes.filter(pk__in=route_pk_list)
+            else:
+                existing_routes = existing_routes.filter(protocol=None)
+        else:
+            existing_routes = existing_routes.filter(protocol=None)
         if sourceports:
             route_pk_list=get_matchingport_route_pks(sourceports, existing_routes)
             if route_pk_list:
@@ -151,7 +160,6 @@ class RouteForm(forms.ModelForm):
                 existing_routes = existing_routes.filter(pk__in=route_pk_list)              
         else:
             existing_routes = existing_routes.filter(port=None)
-        
         for route in existing_routes:
             if name != route.name:
                 existing_url = reverse('edit-route', args=[route.name])
@@ -214,4 +222,13 @@ def get_matchingport_route_pks(portlist, routes):
         rsp = value_list_to_list(route.destinationport.all().values_list('port').order_by('port'))
         if rsp and rsp == ports_value_list:
             route_pk_list.append(route.pk)
+    return route_pk_list
+
+def get_matchingprotocol_route_pks(protocolist, routes):
+    route_pk_list = []
+    protocols_value_list = value_list_to_list(protocolist.values_list('protocol').order_by('protocol'))
+    for route in routes:
+        rsp = value_list_to_list(route.protocol.all().values_list('protocol').order_by('protocol'))
+        if rsp and rsp == protocols_value_list:
+            route_pk_list.append(route.pk)
     return route_pk_list
\ No newline at end of file
diff --git a/flowspec/migrations/0001_initial.py b/flowspec/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..28c5136
--- /dev/null
@@ -0,0 +1,212 @@
+# encoding: 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 'MatchPort'
+        db.create_table(u'match_port', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('port', self.gf('django.db.models.fields.CharField')(unique=True, max_length=24)),
+        ))
+        db.send_create_signal('flowspec', ['MatchPort'])
+
+        # Adding model 'MatchDscp'
+        db.create_table(u'match_dscp', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('dscp', self.gf('django.db.models.fields.CharField')(max_length=24)),
+        ))
+        db.send_create_signal('flowspec', ['MatchDscp'])
+
+        # Adding model 'ThenAction'
+        db.create_table(u'then_action', (
+            ('action', self.gf('django.db.models.fields.CharField')(max_length=60)),
+            ('action_value', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+        ))
+        db.send_create_signal('flowspec', ['ThenAction'])
+
+        # Adding unique constraint on 'ThenAction', fields ['action', 'action_value']
+        db.create_unique(u'then_action', ['action', 'action_value'])
+
+        # Adding model 'Route'
+        db.create_table(u'route', (
+            ('packetlength', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+            ('status', self.gf('django.db.models.fields.CharField')(default='PENDING', max_length=20, null=True, blank=True)),
+            ('last_updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
+            ('expires', self.gf('django.db.models.fields.DateField')(default=datetime.date(2012, 2, 22))),
+            ('protocol', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)),
+            ('name', self.gf('django.db.models.fields.SlugField')(max_length=128, db_index=True)),
+            ('destination', self.gf('django.db.models.fields.CharField')(max_length=32)),
+            ('comments', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+            ('icmptype', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)),
+            ('source', self.gf('django.db.models.fields.CharField')(max_length=32)),
+            ('fragmenttype', self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True)),
+            ('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')(auto_now_add=True, blank=True)),
+            ('tcpflag', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)),
+            ('response', self.gf('django.db.models.fields.CharField')(max_length=512, null=True, blank=True)),
+            ('icmpcode', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+        ))
+        db.send_create_signal('flowspec', ['Route'])
+
+        # Adding M2M table for field sourceport on 'Route'
+        db.create_table(u'route_sourceport', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('route', models.ForeignKey(orm['flowspec.route'], null=False)),
+            ('matchport', models.ForeignKey(orm['flowspec.matchport'], null=False))
+        ))
+        db.create_unique(u'route_sourceport', ['route_id', 'matchport_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'])
+
+        # Adding M2M table for field dscp on 'Route'
+        db.create_table(u'route_dscp', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('route', models.ForeignKey(orm['flowspec.route'], null=False)),
+            ('matchdscp', models.ForeignKey(orm['flowspec.matchdscp'], null=False))
+        ))
+        db.create_unique(u'route_dscp', ['route_id', 'matchdscp_id'])
+
+        # Adding M2M table for field port on 'Route'
+        db.create_table(u'route_port', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('route', models.ForeignKey(orm['flowspec.route'], null=False)),
+            ('matchport', models.ForeignKey(orm['flowspec.matchport'], null=False))
+        ))
+        db.create_unique(u'route_port', ['route_id', 'matchport_id'])
+
+        # Adding M2M table for field destinationport on 'Route'
+        db.create_table(u'route_destinationport', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('route', models.ForeignKey(orm['flowspec.route'], null=False)),
+            ('matchport', models.ForeignKey(orm['flowspec.matchport'], null=False))
+        ))
+        db.create_unique(u'route_destinationport', ['route_id', 'matchport_id'])
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'MatchPort'
+        db.delete_table(u'match_port')
+
+        # Deleting model 'MatchDscp'
+        db.delete_table(u'match_dscp')
+
+        # Deleting model 'ThenAction'
+        db.delete_table(u'then_action')
+
+        # Removing unique constraint on 'ThenAction', fields ['action', 'action_value']
+        db.delete_unique(u'then_action', ['action', 'action_value'])
+
+        # Deleting model 'Route'
+        db.delete_table(u'route')
+
+        # Removing M2M table for field sourceport on 'Route'
+        db.delete_table('route_sourceport')
+
+        # Removing M2M table for field then on 'Route'
+        db.delete_table('route_then')
+
+        # Removing M2M table for field dscp on 'Route'
+        db.delete_table('route_dscp')
+
+        # Removing M2M table for field port on 'Route'
+        db.delete_table('route_port')
+
+        # Removing M2M table for field destinationport on 'Route'
+        db.delete_table('route_destinationport')
+    
+    
+    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': {'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', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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': {'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.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.route': {
+            'Meta': {'object_name': 'Route', 'db_table': "u'route'"},
+            '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'}),
+            'destination': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'destinationport': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchDestinationPort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            'dscp': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flowspec.MatchDscp']", 'null': 'True', 'blank': 'True'}),
+            'expires': ('django.db.models.fields.DateField', [], {'default': 'datetime.date(2012, 2, 22)'}),
+            'filed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'fragmenttype': ('django.db.models.fields.CharField', [], {'max_length': '20', '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'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.SlugField', [], {'max_length': '128', 'db_index': 'True'}),
+            'packetlength': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'port': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchPort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            'protocol': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+            'response': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}),
+            'source': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'sourceport': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchSourcePort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'tcpflag': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
+            'then': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['flowspec.ThenAction']", 'symmetrical': 'False'})
+        },
+        'flowspec.thenaction': {
+            'Meta': {'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']
diff --git a/flowspec/migrations/0002_auto__add_matchprotocol__del_field_route_protocol.py b/flowspec/migrations/0002_auto__add_matchprotocol__del_field_route_protocol.py
new file mode 100644 (file)
index 0000000..40cc4a6
--- /dev/null
@@ -0,0 +1,127 @@
+# encoding: 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 'MatchProtocol'
+        db.create_table(u'match_protocol', (
+            ('protocol', self.gf('django.db.models.fields.CharField')(unique=True, max_length=24)),
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+        ))
+        db.send_create_signal('flowspec', ['MatchProtocol'])
+
+        # Deleting field 'Route.protocol'
+        db.delete_column(u'route', 'protocol')
+
+        # Adding M2M table for field protocol on 'Route'
+        db.create_table(u'route_protocol', (
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+            ('route', models.ForeignKey(orm['flowspec.route'], null=False)),
+            ('matchprotocol', models.ForeignKey(orm['flowspec.matchprotocol'], null=False))
+        ))
+        db.create_unique(u'route_protocol', ['route_id', 'matchprotocol_id'])
+    
+    
+    def backwards(self, orm):
+        
+        # Deleting model 'MatchProtocol'
+        db.delete_table(u'match_protocol')
+
+        # Adding field 'Route.protocol'
+        db.add_column(u'route', 'protocol', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True), keep_default=False)
+
+        # Removing M2M table for field protocol on 'Route'
+        db.delete_table('route_protocol')
+    
+    
+    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': {'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', 'blank': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+            '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': {'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.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'"},
+            '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'}),
+            'destination': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'destinationport': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchDestinationPort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            'dscp': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flowspec.MatchDscp']", 'null': 'True', 'blank': 'True'}),
+            'expires': ('django.db.models.fields.DateField', [], {'default': 'datetime.date(2012, 2, 22)'}),
+            'filed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'fragmenttype': ('django.db.models.fields.CharField', [], {'max_length': '20', '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'}),
+            'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.SlugField', [], {'max_length': '128', 'db_index': 'True'}),
+            'packetlength': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'port': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchPort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            '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'}),
+            'source': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+            'sourceport': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'matchSourcePort'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['flowspec.MatchPort']"}),
+            'status': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'tcpflag': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
+            'then': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['flowspec.ThenAction']", 'symmetrical': 'False'})
+        },
+        'flowspec.thenaction': {
+            'Meta': {'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']
diff --git a/flowspec/migrations/__init__.py b/flowspec/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index 90b8e32..3f9e57f 100644 (file)
@@ -8,12 +8,12 @@ from utils import proxy as PR
 from ipaddr import *
 import datetime
 import logging
-from flowspec.tasks import *
 from time import sleep
 
 import beanstalkc
 from flowspy.utils.randomizer import id_generator as id_gen
 
+from flowspec.tasks import *
 
 FORMAT = '%(asctime)s %(levelname)s: %(message)s'
 logging.basicConfig(format=FORMAT)
@@ -39,6 +39,23 @@ THEN_CHOICES = (
     ("sample", "Sample")                
 )
 
+MATCH_PROTOCOL = (
+    ("ah", "ah"),
+    ("egp", "egp"),
+    ("esp", "esp"),
+    ("gre", "gre"),
+    ("icmp", "icmp"),
+    ("icmp6", "icmp6"),
+    ("igmp", "igmp"),
+    ("ipip", "ipip"),
+    ("ospf", "ospf"),
+    ("pim", "pim"),
+    ("rsvp", "rsvp"),
+    ("sctp", "sctp"),
+    ("tcp", "tcp"),
+    ("udp", "udp"),
+)
+
 ROUTE_STATES = (
     ("ACTIVE", "ACTIVE"),
     ("ERROR", "ERROR"),
@@ -66,6 +83,13 @@ class MatchDscp(models.Model):
     class Meta:
         db_table = u'match_dscp'
 
+class MatchProtocol(models.Model):
+    protocol = models.CharField(max_length=24, unique=True)
+    def __unicode__(self):
+        return self.protocol
+    class Meta:
+        db_table = u'match_protocol'
+
    
 class ThenAction(models.Model):
     action = models.CharField(max_length=60, choices=THEN_CHOICES, verbose_name="Action")
@@ -91,7 +115,7 @@ class Route(models.Model):
     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.CharField(max_length=32, blank=True, null=True, verbose_name="Protocol")
+    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)
@@ -239,17 +263,6 @@ class Route(models.Model):
                         logger.info('Icmp type fields do not match')
                 except:
                     pass
-                try:
-                    assert(self.protocol)
-                    assert(devicematch['protocol'][0])
-                    if self.protocol == devicematch['protocol'][0]:
-                        found = found and True
-                        logger.info('Found a matching protocol')
-                    else:
-                        found = False
-                        logger.info('Protocol fields do not match')
-                except:
-                    pass
                 if found and self.status != "ACTIVE":
                     logger.error('Rule is applied on device but appears as offline')
                     self.status = "ACTIVE"
@@ -284,8 +297,6 @@ class Route(models.Model):
             ret = "%s ICMP Type:<strong>%s</strong><br/>" %(ret, self.icmptype)
         if self.packetlength:
             ret = "%s Packet Length:<strong>%s</strong><br/>" %(ret, self.packetlength)
-        if self.protocol:
-            ret = "%s Protocol:<strong>%s</strong><br/>" %(ret, self.protocol)
         if self.source:
             ret = "%s Src Addr:<strong>%s</strong> <br/>" %(ret, self.source)
         if self.tcpflag:
@@ -293,6 +304,9 @@ class Route(models.Model):
         if self.port:
             for port in self.port.all():
                     ret = ret + "Port:<strong>%s</strong> <br/>" %(port)
+        if self.protocol:
+            for protocol in self.protocol.all():
+                    ret = ret + "Protocol:<strong>%s</strong> <br/>" %(protocol)
         if self.destinationport:
             for port in self.destinationport.all():
                     ret = ret + "Dst Port:<strong>%s</strong> <br/>" %(port)
index e975e07..1502e61 100644 (file)
@@ -85,6 +85,7 @@ def add_route(request):
         form = RouteForm()
         if not request.user.is_superuser:
             form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
+            form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
         return render_to_response('apply.html', {'form': form, 'applier': applier},
                                   context_instance=RequestContext(request))
 
@@ -170,6 +171,7 @@ def edit_route(request, route_slug):
         form = RouteForm(dictionary)
         if not request.user.is_superuser:
             form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
+            form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
         return render_to_response('apply.html', {'form': form, 'edit':True, 'applier': applier},
                                   context_instance=RequestContext(request))
 
index e14b6ee..76f18d3 100644 (file)
@@ -132,7 +132,7 @@ INSTALLED_APPS = (
     'django.contrib.flatpages',
     'flowspec',
     'poller',
-#    'south',
+    'south',
     # Uncomment the next line to enable the admin:
     'django.contrib.admin',
     # Uncomment the next line to enable admin documentation:
@@ -190,6 +190,7 @@ SHIB_LOGOUT_URL = 'https://example.com/Shibboleth.sso/Logout'
 NOTIFY_ADMIN_MAILS = ["admin@admin.com"]
 
 UI_USER_THEN_ACTIONS = ['discard', 'rate-limit']
+UI_USER_PROTOCOLS = ['icmp', 'tcp', 'udp']
 
 PROTECTED_SUBNETS = ['10.10.0.0/16']
 
index 2638a59..7eb94fd 100644 (file)
@@ -285,6 +285,14 @@ div.roundbox, #portsacc, #id_comments{
                         {{ form.destination.help_text }}
                     </p>
                 </div>
+                               <div class="roundbox">
+                    {{ form.protocol.label_tag }}{{ form.protocol }}{% if form.protocol.errors %}
+                    <br>
+                    <p class="error" style="clear:both;">
+                        {{ form.protocol.errors|join:", " }}
+                    </p>
+                    {% endif %}
+                </div>
                 <div id='portsacc'>
                 <h3 style="padding: 0.5em 0.5em 0.5em 0.7em;">Advanced Settings (Ports)</h3>
                 <div class='accord_wrapper' style="height: 452px !important;">
index acf547f..8b4ebb1 100644 (file)
@@ -7,9 +7,8 @@ User {{route.applier.username}} requested the application of the following rule
 Match
 * Dst Addr:{{route.destination}}
 * Src Addr: {{route.source}}
-* Ports:{% for port in route.ports.all %}
-  {{ port }}{% if not forloop.last %}, {% endif %}
-{% endfor %}
+* Protocol:{% for protocol in route.protocol.all %}{{ protocol }}{% if not forloop.last %}, {% endif %}{% endfor %}
+* Ports:{% for port in route.ports.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Source Ports:{% for port in route.sourceport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Destination Ports:{% for port in route.destinationport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 
index 2a7c960..70f390e 100644 (file)
@@ -7,9 +7,8 @@ User {{route.applier.username}} requested the removal of the following rule from
 Match
 * Dst Addr:{{route.destination}}
 * Src Addr: {{route.source}}
-* Ports:{% for port in route.ports.all %}
-  {{ port }}{% if not forloop.last %}, {% endif %}
-{% endfor %}
+* Protocol:{% for protocol in route.protocol.all %}{{ protocol }}{% if not forloop.last %}, {% endif %}{% endfor %}
+* Ports:{% for port in route.ports.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Source Ports:{% for port in route.sourceport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Destination Ports:{% for port in route.destinationport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 
index 974d6c3..cb325b2 100644 (file)
@@ -7,9 +7,8 @@ User {{route.applier.username}} requested the application of the following rule
 Match
 * Dst Addr:{{route.destination}}
 * Src Addr: {{route.source}}
-* Ports:{% for port in route.ports.all %}
-  {{ port }}{% if not forloop.last %}, {% endif %}
-{% endfor %}
+* Protocol:{% for protocol in route.protocol.all %}{{ protocol }}{% if not forloop.last %}, {% endif %}{% endfor %}
+* Ports:{% for port in route.ports.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Source Ports:{% for port in route.sourceport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Destination Ports:{% for port in route.destinationport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 
index 240994d..bf1b180 100644 (file)
@@ -3,9 +3,8 @@ Rule {{route.name}} expires {% ifequal expiration_days 0 %}today{% else%}in {{ex
 Match
 * Dst Addr:{{route.destination}}
 * Src Addr: {{route.source}}
-* Ports:{% for port in route.ports.all %}
-  {{ port }}{% if not forloop.last %}, {% endif %}
-{% endfor %}
+* Protocol:{% for protocol in route.protocol.all %}{{ protocol }}{% if not forloop.last %}, {% endif %}{% endfor %}
+* Ports:{% for port in route.ports.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Source Ports:{% for port in route.sourceport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 * Destination Ports:{% for port in route.destinationport.all %}{{ port }}{% if not forloop.last %}, {% endif %}{% endfor %}
 
index 488bf98..47d0a4c 100644 (file)
@@ -92,8 +92,12 @@ class Applier(object):
                 route.match['source'].append(route_obj.source)
             if route_obj.destination:
                 route.match['destination'].append(route_obj.destination)
-            if route_obj.protocol:
-                route.match['protocol'].append(route_obj.protocol)
+            try:
+                if route_obj.protocol:
+                    for protocol in route_obj.protocol.all():
+                        route.match['protocol'].append(protocol.protocol)
+            except:
+                pass
             try:
                 if route_obj.port:
                     for port in route_obj.port.all():