diff --git a/flowspec/forms.py b/flowspec/forms.py
index 21af0ccc8b85964f48f2ae3e13b4308c304ac6b6..33ce349c67923052c1682e3630658a9f410a9051 100644
--- a/flowspec/forms.py
+++ b/flowspec/forms.py
@@ -26,27 +26,25 @@ from flowspec.models import *
 from peers.models import *
 from accounts.models import *
 from ipaddr import *
+from flowspec.validators import (
+    clean_source,
+    clean_destination,
+    clean_expires,
+    clean_route_form
+)
 from django.core.urlresolvers import reverse
 from django.contrib.auth.models import User
 from django.conf import settings
 import datetime
-from django.core.mail import mail_admins, mail_managers, send_mail
+from django.core.mail import send_mail
+
 
 class UserProfileForm(forms.ModelForm):
     class Meta:
         model = UserProfile
 
-class RouteForm(forms.ModelForm):
-#    name = forms.CharField(help_text=ugettext_lazy("A unique route name,"
-#                                         " e.g. uoa_block_p80"), label=ugettext_lazy("Route Name"), required=False)
-#    source = forms.CharField(help_text=ugettext_lazy("A qualified IP Network address. CIDR notation,"
-#                                         " e.g.10.10.0.1/32"), label=ugettext_lazy("Source Address"), required=False)
-#    source_ports = forms.ModelMultipleChoiceField(queryset=MatchPort.objects.all(), help_text=ugettext_lazy("A set of source ports to block"), label=ugettext_lazy("Source Ports"), required=False)
-#    destination = forms.CharField(help_text=ugettext_lazy("A qualified IP Network address. CIDR notation,"
-#                                         " e.g.10.10.0.1/32"), label=ugettext_lazy("Destination Address"), required=False)
-#    destination_ports = forms.ModelMultipleChoiceField(queryset=MatchPort.objects.all(), help_text=ugettext_lazy("A set of destination ports to block"), label=ugettext_lazy("Destination Ports"), required=False)
-#    ports = forms.ModelMultipleChoiceField(queryset=MatchPort.objects.all(), help_text=ugettext_lazy("A set of ports to block"), label=ugettext_lazy("Ports"), required=False)
 
+class RouteForm(forms.ModelForm):
     class Meta:
         model = Route
 
@@ -58,142 +56,59 @@ class RouteForm(forms.ModelForm):
             raise forms.ValidationError('This field is required.')
 
     def clean_source(self):
-        user = User.objects.get(pk=self.data['applier'])
-        peers = user.get_profile().peers.all()
-        peers_names = ''.join(('%s, ' % (peer.peer_name)) for peer in peers)[:-2]
-        data = self.cleaned_data['source']
-        private_error = False
-        protected_error = False
-        networkaddr_error = False
-        broadcast_error = False
-        if data:
-            try:
-                address = IPNetwork(data)
-                for net in settings.PROTECTED_SUBNETS:
-                    if address in IPNetwork(net):
-                        protected_error = True
-                        mail_body = "User %s %s (%s) attempted to set %s as the source address in a firewall rule" % (user.username, user.email, peers_names, data)
-                        send_mail(settings.EMAIL_SUBJECT_PREFIX + "Caught an attempt to set a protected IP/network as a source address",
-                              mail_body, settings.SERVER_EMAIL,
-                              settings.NOTIFY_ADMIN_MAILS, fail_silently=True)
-                        raise Exception
-                if address.is_private:
-                    private_error = True
-                    raise Exception
-                if address.version == 4 and int(address.prefixlen) == 32:
-                    if int(address.network.compressed.split('.')[-1]) == 0:
-                        broadcast_error = True
-                        raise Exception
-                    elif int(address.network.compressed.split('.')[-1]) == 255:
-                        networkaddr_error = True
-                        raise Exception
-                return self.cleaned_data["source"]
-            except Exception:
-                error_text = _('Invalid network address format')
-                if private_error:
-                    error_text = _('Private addresses not allowed')
-                if networkaddr_error:
-                    error_text = _('Malformed address format. Cannot be ...255/32')
-                if broadcast_error:
-                    error_text = _('Malformed address format. Cannot be ...0/32')
-                if protected_error:
-                    error_text = _('You have no authority on this subnet')
-                raise forms.ValidationError(error_text)
+        # 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):
-        user = User.objects.get(pk=self.data['applier'])
-        peers = user.get_profile().peers.all()
-        peers_names = ''.join(('%s, ' % (peer.peer_name)) for peer in peers)[:-2]
-        data = self.cleaned_data['destination']
-        error = None
-        protected_error = False
-        networkaddr_error = False
-        broadcast_error = False
-        if data:
-            try:
-                address = IPNetwork(data)
-                for net in settings.PROTECTED_SUBNETS:
-                    if address in IPNetwork(net):
-                        protected_error = True
-                        mail_body = "User %s %s (%s) attempted to set %s as the destination address in a firewall rule" % (user.username, user.email, peers_names, data)
-                        send_mail(settings.EMAIL_SUBJECT_PREFIX + "Caught an attempt to set a protected IP/network as the destination address",
-                              mail_body, settings.SERVER_EMAIL,
-                              settings.NOTIFY_ADMIN_MAILS, fail_silently=True)
-                        raise Exception
-                if address.prefixlen < settings.PREFIX_LENGTH:
-                    error = _("Currently no prefix lengths < %s are allowed") % settings.PREFIX_LENGTH
-                    raise Exception
-                if address.version == 4 and int(address.prefixlen) == 32:
-                    if int(address.network.compressed.split('.')[-1]) == 0:
-                        broadcast_error = True
-                        raise Exception
-                    elif int(address.network.compressed.split('.')[-1]) == 255:
-                        networkaddr_error = True
-                        raise Exception
-                return self.cleaned_data["destination"]
-            except Exception:
-                error_text = _('Invalid network address format')
-                if error:
-                    error_text = error
-                if protected_error:
-                    error_text = _('You have no authority on this subnet')
-                if networkaddr_error:
-                    error_text = _('Malformed address format. Cannot be ...255/32')
-                if broadcast_error:
-                    error_text = _('Malformed address format. Cannot be ...0/32')
-                raise forms.ValidationError(error_text)
+        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 date:
-            range_days = (date - datetime.date.today()).days
-            if range_days > 0 and range_days < 11:
-                return self.cleaned_data["expires"]
-            else:
-                raise forms.ValidationError('Invalid date range')
+        res = clean_expires(date)
+        if date != res:
+            raise forms.ValidationError(res)
+        return res
 
     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__peer__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)
         ports = self.cleaned_data.get('port', None)
-        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)
-        issuperuser = self.data.get('issuperuser')
-        peers = user.get_profile().peers.all()
-        networks = []
-        for peer in peers:
-            networks.extend(peer.networks.all())
-        if issuperuser:
-            networks = PeerRange.objects.filter(peer__in=Peer.objects.all()).distinct()
-        mynetwork = False
-        route_pk_list = []
-        if destination:
-            for network in networks:
-                net = IPNetwork(network.network)
-                if IPNetwork(destination) in net:
-                    mynetwork = True
-            if not mynetwork:
-                raise forms.ValidationError(_('Destination address/network should belong to your administrative address space. Check My Profile to review your networks'))
-        if (sourceports and ports):
-            raise forms.ValidationError(_('Cannot create rule for source ports and ports at the same time. Select either ports or source ports'))
-        if (destinationports and ports):
-            raise forms.ValidationError(_('Cannot create rule for destination ports and ports at the same time. Select either ports or destination ports'))
-        if sourceports and not source:
-            raise forms.ValidationError(_('Once source port is matched, source has to be filled as well. Either deselect source port or fill source address'))
-        if destinationports and not destination:
-            raise forms.ValidationError(_('Once destination port is matched, destination has to be filled as well. Either deselect destination port or fill destination address'))
-        if not (source or sourceports or ports or destination or destinationports):
-            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.all()
-        existing_routes = existing_routes.filter(applier__userprofile__peer__in=peers)
+
         if source:
             source = IPNetwork(source).compressed
             existing_routes = existing_routes.filter(source=source)
diff --git a/flowspec/serializers.py b/flowspec/serializers.py
index 90d56557c37301f7fa06ba05cc4477b0249c47b3..287b53355dd47b8edfa158520b80e122d986a545 100644
--- a/flowspec/serializers.py
+++ b/flowspec/serializers.py
@@ -6,12 +6,55 @@ from flowspec.models import (
     FragmentType,
     MatchProtocol
 )
+from flowspec.validators import (
+    clean_source,
+    clean_destination,
+    clean_expires,
+    check_if_rule_exists
+)
 
 
-# Serializers define the API representation.
 class RouteSerializer(serializers.HyperlinkedModelSerializer):
     applier = serializers.CharField(source='applier_username', read_only=True)
 
+    def validate(self, data):
+        user = self.context.get('request').user
+        # validate source
+        source = data.get('source')
+        res = clean_source(
+            user,
+            source
+        )
+        if res != source:
+            raise serializers.ValidationError(res)
+
+        # validate destination
+        destination = data.get('destination')
+        res = clean_destination(
+            user,
+            destination
+        )
+        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'),
+            'destination': data.get('destination'),
+        }
+        exists = check_if_rule_exists(fields)
+        if exists:
+            raise serializers.ValidationError(exists)
+        return data
+
     class Meta:
         model = Route
         fields = (
@@ -37,7 +80,7 @@ class RouteSerializer(serializers.HyperlinkedModelSerializer):
             'expires',
             'response',
             'comments',
-            'requesters_address'
+            'requesters_address',
         )
         read_only_fields = ('status', 'expires', 'requesters_address', 'response')
 
diff --git a/flowspec/validators.py b/flowspec/validators.py
new file mode 100644
index 0000000000000000000000000000000000000000..85c84e73add320e1c6442d72e4e4f4da0981d8b8
--- /dev/null
+++ b/flowspec/validators.py
@@ -0,0 +1,153 @@
+from ipaddr import IPNetwork
+import datetime
+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 django.core.urlresolvers import reverse
+
+
+def get_network(ip):
+    try:
+        address = IPNetwork(ip)
+    except Exception:
+        return (False, _('Invalid network address format'))
+    else:
+        return (True, address)
+
+
+def clean_ip(address):
+    if address.is_private:
+            return _('Private addresses not allowed')
+
+    if address.version == 4 and int(address.prefixlen) == 32:
+        if int(address.network.compressed.split('.')[-1]) == 0:
+            return _('Malformed address format. Cannot be ...0/32')
+        elif int(address.network.compressed.split('.')[-1]) == 255:
+            return _('Malformed address format. Cannot be ...255/32')
+
+
+def clean_source(user, source):
+    success, address = get_network(source)
+    if not success:
+        return address
+    for net in settings.PROTECTED_SUBNETS:
+        if address in IPNetwork(net):
+            mail_body = "User %s %s attempted to set %s as the source address in a firewall rule" % (user.username, user.email, source)
+            send_mail(
+                settings.EMAIL_SUBJECT_PREFIX + "Caught an attempt to set a protected IP/network as a source address",
+                mail_body,
+                settings.SERVER_EMAIL,
+                settings.NOTIFY_ADMIN_MAILS,
+                fail_silently=True
+            )
+            return _('You have no authority on this subnet')
+    return source
+
+
+def clean_destination(user, destination):
+    success, address = get_network(destination)
+    if not success:
+        return address
+    for net in settings.PROTECTED_SUBNETS:
+        if address in IPNetwork(net):
+            mail_body = "User %s %s attempted to set %s as the destination address in a firewall rule" % (user.username, user.email, destination)
+            send_mail(
+                settings.EMAIL_SUBJECT_PREFIX + "Caught an attempt to set a protected IP/network as the destination address",
+                mail_body, settings.SERVER_EMAIL,
+                settings.NOTIFY_ADMIN_MAILS,
+                fail_silently=True
+            )
+            return _('You have no authority on this subnet')
+    # make sure its a network prefix that
+    # can be used, depending on settings.PREFIX_LENGTH
+    if address.prefixlen < settings.PREFIX_LENGTH:
+        return _("Currently no prefix lengths < %s are allowed") % settings.PREFIX_LENGTH
+
+    # make sure its a valid ip
+    error = clean_ip(address)
+
+    # make sure user can apply rule in these networks
+    if error:
+        return error
+    if not user.is_superuser:
+        networks = PeerRange.objects.filter(peer__in=user.userprofile.peers.all())
+    else:
+        networks = PeerRange.objects.filter(peer__in=Peer.objects.all()).distinct()
+    network_is_mine = False
+    for network in networks:
+        net = IPNetwork(network.network)
+        if IPNetwork(destination) in net:
+            network_is_mine = True
+    if not network_is_mine:
+        return (_('Destination address/network should belong to your administrative address space. Check My Profile to review your networks'))
+    return destination
+
+
+def clean_expires(date):
+    if date:
+        range_days = (date - datetime.date.today()).days
+        if range_days > 0 and range_days < 11:
+            return date
+        else:
+            return _('Invalid date range')
+
+
+def value_list_to_list(valuelist):
+    vl = []
+    for val in valuelist:
+        vl.append(val[0])
+    return vl
+
+
+def get_matchingport_route_pks(portlist, routes):
+    route_pk_list = []
+    ports_value_list = value_list_to_list(portlist.values_list('port').order_by('port'))
+    for route in 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
+
+
+def clean_route_form(data):
+    source = data.get('source', None)
+    sourceports = data.get('sourceport', None)
+    ports = data.get('port', None)
+    then = data.get('then', None)
+    destination = data.get('destination', None)
+    destinationports = data.get('destinationport', None)
+    user = data.get('applier', None)
+    if (sourceports and ports):
+        return _('Cannot create rule for source ports and ports at the same time. Select either ports or source ports')
+    if (destinationports and ports):
+        return _('Cannot create rule for destination ports and ports at the same time. Select either ports or destination ports')
+    if sourceports and not source:
+        return _('Once source port is matched, source has to be filled as well. Either deselect source port or fill source address')
+    if destinationports and not destination:
+        return _('Once destination port is matched, destination has to be filled as well. Either deselect destination port or fill destination address')
+    if not (source or sourceports or ports or destination or destinationports):
+        return _('Fill at least a Rule Match Condition')
+    if not user.is_superuser and then[0].action not in settings.UI_USER_THEN_ACTIONS:
+        return _('This action "%s" is not permitted') % (then[0].action)
+
+
+def check_if_rule_exists(fields):
+    routes = Route.objects.filter(
+        source=fields.get('source'),
+        destination=IPNetwork(fields.get('destination')).compressed,
+    )
+    for route in routes:
+        return _('Rule exists: %s' % reverse('edit-route', args=[route.name]))
+    return False
diff --git a/flowspec/viewsets.py b/flowspec/viewsets.py
index d7f75b4b2a17c0d041047473911483d1b17dd24d..ee6f9ea17eaaae7e6fd23d2b9cf22145e8d0eeda 100644
--- a/flowspec/viewsets.py
+++ b/flowspec/viewsets.py
@@ -1,5 +1,6 @@
 from django.shortcuts import get_object_or_404
 from django.conf import settings
+from rest_framework.exceptions import PermissionDenied
 
 from rest_framework import viewsets
 from flowspec.models import (
@@ -32,7 +33,7 @@ class RouteViewSet(viewsets.ModelViewSet):
             elif self.request.user.is_authenticated():
                 return Route.objects.filter(applier=self.request.user)
             else:
-                raise Exception('User is not Authenticated')
+                raise PermissionDenied('User is not Authenticated')
 
         if self.request.user.is_superuser:
             return Route.objects.all()
@@ -43,6 +44,10 @@ class RouteViewSet(viewsets.ModelViewSet):
         serializer = RouteSerializer(self.get_queryset(), many=True, context={'request': request})
         return Response(serializer.data)
 
+    def create(self, request):
+        serializer = RouteSerializer(context={'request': request})
+        return super(RouteViewSet, self).create(request)
+
     def retrieve(self, request, pk=None):
         route = get_object_or_404(self.get_queryset(), pk=pk)
         serializer = RouteSerializer(route)
@@ -57,7 +62,7 @@ class RouteViewSet(viewsets.ModelViewSet):
             elif self.request.user.is_authenticated():
                 obj.applier = self.request.user
             else:
-                raise Exception('User is not Authenticated')
+                raise PermissionDenied('User is not Authenticated')
         else:
             obj.applier = self.request.user