diff --git a/flowspec/admin.py b/flowspec/admin.py index 283bd642aed5ebb7435201f6d2b9bfacca95ea7b..f6c3ad9e3078805419f162345a49e5042dab8c69 100644 --- a/flowspec/admin.py +++ b/flowspec/admin.py @@ -10,33 +10,41 @@ class RouteAdmin(admin.ModelAdmin): applier = PR.Applier(route_objects=queryset) commit, response = applier.apply(configuration=applier.delete_routes()) if commit: - rows = queryset.update(is_online=False) + rows = queryset.update(is_online=False, is_active=False) queryset.update(response="Successfully removed route from network") self.message_user(request, "Successfully removed %s routes from network" % rows) else: self.message_user(request, "Could not remove routes from network") - deactivate.short_description = "Remove selected routes from network" - - list_display = ('name', 'get_match', 'get_then', 'is_online', 'applier', 'response') - fields = ('name', 'match','then','applier', 'expires') + deactivate.short_description = "Deactivate selected routes from network" + + list_display = ('name', 'is_online', 'applier', 'get_match', 'get_then', 'response') + fieldsets = [ + (None, {'fields': ['name',]}), + ("Match", {'fields': ['source', 'sourceport', 'destination', 'destinationport', 'port']}), + ('Advanced Match Statements', {'fields': ['dscp', 'fragmenttype', 'icmpcode', 'icmptype', 'packetlength', 'protocol', 'tcpflag'], 'classes': ['collapse']}), + ("Then", {'fields': ['then' ]}), + (None, {'fields': ['comments',]}), + + ] +# fields = ('name', 'applier', 'expires') #def formfield_for_dbfield(self, db_field, **kwargs): # if db_field.name == 'password': # kwargs['widget'] = PasswordInput # return db_field.formfield(**kwargs) -admin.site.register(MatchAddress) +#admin.site.register(MatchAddress) admin.site.register(MatchPort) admin.site.register(MatchDscp) -admin.site.register(MatchFragmentType) -admin.site.register(MatchIcmpCode) -admin.site.register(MatchIcmpType) -admin.site.register(MatchPacketLength) -admin.site.register(MatchProtocol) -admin.site.register(MatchTcpFlag) +#admin.site.register(MatchFragmentType) +#admin.site.register(MatchIcmpCode) +#admin.site.register(MatchIcmpType) +#admin.site.register(MatchPacketLength) +#admin.site.register(MatchProtocol) +#admin.site.register(MatchTcpFlag) admin.site.register(ThenAction) -admin.site.register(ThenStatement) -admin.site.register(MatchStatement) +#admin.site.register(ThenStatement) +#admin.site.register(MatchStatement) admin.site.register(Route, RouteAdmin) admin.site.disable_action('delete_selected') diff --git a/flowspec/models.py b/flowspec/models.py index eb9c44b9b250579e8b2d847d8f329ccd3712020a..b3f917b84d3926dd943a89303cad75ed52a7dd0b 100644 --- a/flowspec/models.py +++ b/flowspec/models.py @@ -2,9 +2,11 @@ # vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab from django.db import models +from django.conf import settings from django.contrib.auth.models import User from utils import proxy as PR from ipaddr import * +from datetime import * import logging FORMAT = '%(asctime)s %(levelname)s: %(message)s' @@ -32,23 +34,8 @@ THEN_CHOICES = ( ) +def days_offset(): return datetime.now() + timedelta(days = settings.EXPIRATION_DAYS_OFFSET) -class MatchAddress(models.Model): - address = models.CharField(max_length=255, help_text=u"Network address. Use address/CIDR notation") - def __unicode__(self): - return self.address - - def clean(self, *args, **kwargs): - from django.core.exceptions import ValidationError - try: - address = IPNetwork(self.address) - self.address = address.exploded - except Exception: - raise ValidationError('Invalid network address format') - - class Meta: - db_table = u'match_address' - class MatchPort(models.Model): port = models.CharField(max_length=24) def __unicode__(self): @@ -65,70 +52,72 @@ class MatchDscp(models.Model): class ThenAction(models.Model): - action = models.CharField(max_length=60, choices=THEN_CHOICES) - action_value = models.CharField(max_length=255, blank=True, null=True) + action = models.CharField(max_length=60, choices=THEN_CHOICES, verbose_name="Action") + action_value = models.CharField(max_length=255, blank=True, null=True, verbose_name="Action Value") def __unicode__(self): - return "%s %s" %(self.action, self.action_value) + return "%s: %s" %(self.action, self.action_value) class Meta: db_table = u'then_action' class Route(models.Model): name = models.CharField(max_length=128) applier = models.ForeignKey(User) - destination = models.CharField(max_length=32, blank=True, null=True, help_text=u"Network address. Use address/CIDR notation") - destinationport = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchDestinationPort") - dscp = models.ManyToManyField(MatchDscp, blank=True, null=True) - fragmenttype = models.CharField(max_length=20, choices=FRAGMENT_CODES, blank=True, null=True) - icmpcode = models.CharField(max_length=32, blank=True, null=True) - icmptype = models.CharField(max_length=32, blank=True, null=True) - packetlength = models.IntegerField(blank=True, null=True) - port = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchPort") - protocol = models.CharField(max_length=32, blank=True, null=True) - source = models.CharField(max_length=32, blank=True, null=True, help_text=u"Network address. Use address/CIDR notation") - sourceport = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchSourcePort") - tcpflag = models.CharField(max_length=128, blank=True, null=True) - then = models.ManyToManyField(ThenAction) + source = models.CharField(max_length=32, blank=True, null=True, help_text=u"Network address. Use address/CIDR notation", verbose_name="Source Address") + sourceport = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchSourcePort", verbose_name="Source Port") + destination = models.CharField(max_length=32, blank=True, null=True, help_text=u"Network address. Use address/CIDR notation", verbose_name="Destination Address") + destinationport = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchDestinationPort", verbose_name="Destination Port") + port = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchPort", verbose_name="Port" ) + dscp = models.ManyToManyField(MatchDscp, blank=True, null=True, verbose_name="DSCP") + fragmenttype = models.CharField(max_length=20, choices=FRAGMENT_CODES, 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.CharField(max_length=32, 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) is_online = models.BooleanField(default=False) is_active = models.BooleanField(default=False) - expires = models.DateTimeField() + expires = models.DateField(default=days_offset) response = models.CharField(max_length=512, blank=True, null=True) - comments = models.TextField(null=True, blank=True) + comments = models.TextField(null=True, blank=True, verbose_name="Comments") def __unicode__(self): return self.name class Meta: + unique_together = (("name", "is_active"),) db_table = u'route' def clean(self, *args, **kwargs): from django.core.exceptions import ValidationError if self.destination: try: - address = IPNetwork(self.address) - self.address = address.exploded + address = IPNetwork(self.destination) + self.destination = address.exploded except Exception: - raise ValidationError('Invalid network address format') + raise ValidationError('Invalid network address format at Destination Field') if self.source: try: - address = IPNetwork(self.address) - self.address = address.exploded + address = IPNetwork(self.source) + self.source = address.exploded except Exception: - raise ValidationError('Invalid network address format') + raise ValidationError('Invalid network address format at Source Field') def save(self, *args, **kwargs): applier = PR.Applier(route_object=self) commit, response = applier.apply() if commit: self.is_online = True + self.is_active = True self.response = response else: self.is_online = False self.response = response super(Route, self).save(*args, **kwargs) - + def is_synced(self): found = False @@ -144,11 +133,10 @@ class Route(models.Model): found = True logger.info('Found a matching route name') devicematch = route.match - routematch = self.match try: - assert(routematch.matchDestination.address) + assert(self.destination) assert(devicematch['destination'][0]) - if routematch.matchDestination.address == devicematch['destination'][0]: + if self.destination == devicematch['destination'][0]: found = found and True logger.info('Found a matching destination') else: @@ -157,9 +145,9 @@ class Route(models.Model): except: pass try: - assert(routematch.matchSource.address) + assert(self.source) assert(devicematch['source'][0]) - if routematch.matchSource.address == devicematch['source'][0]: + if self.source == devicematch['source'][0]: found = found and True logger.info('Found a matching source') else: @@ -168,9 +156,9 @@ class Route(models.Model): except: pass try: - assert(routematch.matchfragmenttype.fragmenttype) + assert(self.fragmenttype) assert(devicematch['fragment'][0]) - if routematch.matchfragmenttype.fragmenttype == devicematch['fragment'][0]: + if self.fragmenttype == devicematch['fragment'][0]: found = found and True logger.info('Found a matching fragment type') else: @@ -179,9 +167,9 @@ class Route(models.Model): except: pass try: - assert(routematch.matchicmpcode.icmp_code) + assert(self.icmpcode) assert(devicematch['icmp-code'][0]) - if routematch.matchicmpcode.icmp_code == devicematch['icmp-code'][0]: + if self.icmpcode == devicematch['icmp-code'][0]: found = found and True logger.info('Found a matching icmp code') else: @@ -190,9 +178,9 @@ class Route(models.Model): except: pass try: - assert(routematch.matchicmptype.icmp_type) + assert(self.icmptype) assert(devicematch['icmp-type'][0]) - if routematch.matchicmpcode.icmp_type == devicematch['icmp-type'][0]: + if self.icmptype == devicematch['icmp-type'][0]: found = found and True logger.info('Found a matching icmp type') else: @@ -201,9 +189,9 @@ class Route(models.Model): except: pass try: - assert(routematch.matchprotocol.protocol) + assert(self.protocol) assert(devicematch['protocol'][0]) - if routematch.matchprotocol.protocol == devicematch['protocol'][0]: + if self.protocol == devicematch['protocol'][0]: found = found and True logger.info('Found a matching protocol') else: @@ -217,10 +205,9 @@ class Route(models.Model): return found - def get_then(self): ret = '' - then_statements = self.then.thenaction.all() + then_statements = self.then.all() for statement in then_statements: if statement.action_value: ret = "%s %s:<strong>%s</strong><br/>" %(ret, statement.action, statement.action_value) @@ -230,37 +217,36 @@ class Route(models.Model): get_then.short_description = 'Then statement' get_then.allow_tags = True - +# def get_match(self): ret = '' - match = self.match - if match.matchDestination: - ret = ret = '%s Destination Address:<strong>%s</strong><br/>' %(ret, match.matchDestination) - if match.matchfragmenttype: - ret = ret = "%s Fragment Type:<strong>%s</strong><br/>" %(ret, match.matchfragmenttype) - if match.matchicmpcode: - ret = ret = "%s ICMP code:<strong>%s</strong><br/>" %(ret, match.matchicmpcode) - if match.matchicmptype: - ret = ret = "%s ICMP Type:<strong>%s</strong><br/>" %(ret, match.matchicmptype) - if match.matchpacketlength: - ret = ret = "%s Packet Length:<strong>%s</strong><br/>" %(ret, match.matchpacketlength) - if match.matchprotocol: - ret = ret = "%s Protocol:<strong>%s</strong><br/>" %(ret, match.matchprotocol) - if match.matchSource: - ret = ret = "%s Source Address:<strong>%s</strong><br/>" %(ret, match.matchSource) - if match.matchTcpFlag: - ret = ret = "%s TCP flag:<strong>%s</strong><br/>" %(ret, match.matchTcpFlag) - if match.matchport: - for port in match.matchport.all(): + if self.destination: + ret = ret = '%s Destination Address:<strong>%s</strong><br/>' %(ret, self.destination) + if self.fragmenttype: + ret = ret = "%s Fragment Type:<strong>%s</strong><br/>" %(ret, self.fragmenttype) + if self.icmpcode: + ret = ret = "%s ICMP code:<strong>%s</strong><br/>" %(ret, self.icmpcode) + if self.icmptype: + ret = ret = "%s ICMP Type:<strong>%s</strong><br/>" %(ret, self.icmptype) + if self.packetlength: + ret = ret = "%s Packet Length:<strong>%s</strong><br/>" %(ret, self.packetlength) + if self.protocol: + ret = ret = "%s Protocol:<strong>%s</strong><br/>" %(ret, self.protocol) + if self.source: + ret = ret = "%s Source Address:<strong>%s</strong><br/>" %(ret, self.source) + if self.tcpflag: + ret = ret = "%s TCP flag:<strong>%s</strong><br/>" %(ret, self.tcpflag) + if self.port: + for port in self.port.all(): ret = "%s Port:<strong>%s</strong><br/>" %(ret, port) - if match.matchDestinationPort: - for port in match.matchDestinationPort.all(): + if self.destinationport: + for port in self.destinationport.all(): ret = "%s Port:<strong>%s</strong><br/>" %(ret, port) - if match.matchSourcePort: - for port in match.matchSourcePort.all(): + if self.sourceport: + for port in self.sourceport.all(): ret = "%s Port:<strong>%s</strong><br/>" %(ret, port) - if match.matchdscp: - for dscp in match.matchdscp.all(): + if self.dscp: + for dscp in self.dscp.all(): ret = "%s Port:<strong>%s</strong><br/>" %(ret, dscp) return ret.rstrip('<br/>') diff --git a/flowspec_dev.db b/flowspec_dev.db new file mode 100644 index 0000000000000000000000000000000000000000..9a32e30710d85f24c691b2c2a8e55e0697254adc Binary files /dev/null and b/flowspec_dev.db differ diff --git a/utils/proxy.py b/utils/proxy.py index 46bc5da5e65fa06c90dd0b6ac0bfb2dd766cf3a4..a845d185b7be273738ebe2b262282385b2485f91 100644 --- a/utils/proxy.py +++ b/utils/proxy.py @@ -66,35 +66,45 @@ class Applier(object): flow.routes.append(route) device.routing_options.append(flow) route.name = route_obj.name - match = route_obj.match - if match.matchSource: - route.match['source'].append(match.matchSource.address) - if match.matchDestination: - route.match['destination'].append(match.matchDestination.address) - if match.matchprotocol: - route.match['protocol'].append(match.matchprotocol.protocol) - if match.matchport: - for port in match.matchport.all(): - route.match['port'].append(port.port) - if match.matchDestinationPort: - for port in match.matchDestinationPort.all(): - route.match['destination-port'].append(port.port) - if match.matchSourcePort: - for port in match.matchSourcePort.all(): - route.match['source-port'].append(port.port) - if match.matchicmpcode: - route.match['icmp-code'].append(match.matchicmpcode.icmp_code) - if match.matchicmptype: - route.match['icmp-type'].append(match.matchicmptype.icmp_type) - if match.matchTcpFlag: - route.match['tcp-flags'].append(match.matchTcpFlag.tcp_flags) - if match.matchdscp: - for dscp in match.matchdscp.all(): - route.match['dscp'].append(dscp.dscp) - if match.matchfragmenttype: - route.match['fragment'].append(match.matchfragmenttype.fragmenttype) - then = route_obj.then - for thenaction in then.thenaction.all(): + if route_obj.source: + 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.port: + for port in route_obj.port.all(): + route.match['port'].append(port.port) + except: + pass + try: + if route_obj.destinationport: + for port in route_obj.destinationport.all(): + route.match['destination-port'].append(port.port) + except: + pass + try: + if route_obj.sourceport: + for port in route_obj.sourceport.all(): + route.match['source-port'].append(port.port) + except: + pass + if route_obj.icmpcode: + route.match['icmp-code'].append(route_obj.icmpcode) + if route_obj.icmptype: + route.match['icmp-type'].append(route_obj.icmptype) + if route_obj.tcpflag: + route.match['tcp-flags'].append(route_obj.tcpflag) + try: + if route_obj.dscp: + for dscp in route_obj.dscp.all(): + route.match['dscp'].append(dscp.dscp) + except: + pass + if route_obj.fragmenttype: + route.match['fragment'].append(route_obj.fragmenttype) + for thenaction in route_obj.then.all(): if thenaction.action_value: route.then[thenaction.action] = thenaction.action_value else: