From: Stauros Kroustouris Date: Fri, 5 Dec 2014 15:18:43 +0000 (+0200) Subject: generate the rule name in junos X-Git-Url: https://code.grnet.gr/git/flowspy/commitdiff_plain/7ae0e0ec4604a3363386ec307eaad6002ed8bd8d generate the rule name in junos --- diff --git a/flowspec/junos.py b/flowspec/junos.py new file mode 100644 index 0000000..ce8173d --- /dev/null +++ b/flowspec/junos.py @@ -0,0 +1,207 @@ +PROTOCOL_NUMBERS = { + 'HOPOPT': '0', + 'ICMP': '1', + 'IGMP': '2', + 'GGP': '3', + 'IPv4': '4', + 'ST': '5', + 'TCP': '6', + 'CBT': '7', + 'EGP': '8', + 'IGP': '9', + 'BBN-RCC-MON': '10', + 'NVP-II': '11', + 'PUP': '12', + 'ARGUS': '13', + 'EMCON': '14', + 'XNET': '15', + 'CHAOS': '16', + 'UDP': '17', + 'MUX': '18', + 'DCN-MEAS': '19', + 'HMP': '20', + 'PRM': '21', + 'XNS-IDP': '22', + 'TRUNK-1': '23', + 'TRUNK-2': '24', + 'LEAF-1': '25', + 'LEAF-2': '26', + 'RDP': '27', + 'IRTP': '28', + 'ISO-TP4': '29', + 'NETBLT': '30', + 'MFE-NSP': '31', + 'MERIT-INP': '32', + 'DCCP': '33', + '3PC': '34', + 'IDPR': '35', + 'XTP': '36', + 'DDP': '37', + 'IDPR-CMTP': '38', + 'TP++': '39', + 'IL': '40', + 'IPv6': '41', + 'SDRP': '42', + 'IPv6-Route': '43', + 'IPv6-Frag ': '44', + 'IDRP': '45', + 'RSVP': '46', + 'GRE': '47', + 'DSR': '48', + 'BNA': '49', + 'ESP': '50', + 'AH': '51', + 'I-NLSP': '52', + 'SWIPE': '53', + 'NARP': '54', + 'MOBILE': '55', + 'TLSP': '56', + 'SKIP': '57', + 'IPv6-ICMP': '58', + 'IPv6-NoNxt': '59', + 'IPv6-Opts': '60', + 'CFTP': '62', + 'SAT-EXPAK': '64', + 'KRYPTOLAN': '65', + 'RVD': '66', + 'IPPC': '67', + 'SAT-MON': '69', + 'VISA': '70', + 'IPCV': '71', + 'CPNX': '72', + 'CPHB': '73', + 'WSN': '74', + 'PVP': '75', + 'BR-SAT-MON': '76', + 'SUN-ND': '77', + 'WB-MON': '78', + 'WB-EXPAK': '79', + 'ISO-IP': '80', + 'VMTP': '81', + 'SECURE-VMTP': '82', + 'VINES': '83', + 'TTP': '84', + 'IPTM': '84', + 'NSFNET-IGP': '85', + 'DGP': '86', + 'TCF': '87', + 'EIGRP': '88', + 'OSPFIGP': '89', + 'Sprite-RPC': '90', + 'LARP': '91', + 'MTP': '92', + 'AX.25': '93', + 'IPIP': '94', + 'MICP': '95', + 'SCC-SP': '96', + 'ETHERIP': '97', + 'ENCAP': '98', + 'GMTP': '100', + 'IFMP': '101', + 'PNNI': '102', + 'PIM': '103', + 'ARIS': '104', + 'SCPS': '105', + 'QNX': '106', + 'A/N': '107', + 'IPComp': '108', + 'SNP': '109', + 'Compaq-Peer': '110', + 'IPX-in-IP': '111', + 'VRRP': '112', + 'PGM': '113', + 'L2TP': '115', + 'DDX': '116', + 'IATP': '117', + 'STP': '118', + 'SRP': '119', + 'UTI': '120', + 'SMP': '121', + 'SM': '122', + 'PTP ': '123', + 'ISIS': '124', + 'FIRE': '125', + 'CRTP': '126', + 'CRUDP': '127', + 'SSCOPMCE': '128', + 'IPLT': '129', + 'SPS': '130', + 'PIPE': '131', + 'SCTP': '132', + 'FC': '133', + 'RSVP-E2E-IGNORE': '134', + 'Mobility Header': '135', + 'UDPLite': '136', + 'MPLS-in-IP': '137', + 'manet': '138', + 'HIP': '139', + 'Shim6': '140', + 'WESP': '141', + 'ROHC': '142' +} + + +def get_protocols_numbers(protocols_set): + protocols = 'proto' + for protocol in protocols_set: + protocols += '=%s,' % PROTOCOL_NUMBERS.get(protocol.protocol.upper()) + return protocols + + +def get_range(addr_range): + if '/32' in addr_range: + addr_range = addr_range.replace('/32', '') + if len(addr_range.split('/')) > 1: + mask = addr_range.split('/')[1] + else: + mask = False + elements = addr_range.split('/')[0].split('.') + if '0' in elements: + if elements == ['0', '0', '0', '0']: + addr_range = '0' + if mask is not False: + addr_range += '/%s' % mask + elif elements[1:] == ['0', '0', '0']: + addr_range = '.'.join(elements[:2]) + if mask is not False: + addr_range += '/%s' % mask + elif elements[2:] == ['0', '0']: + addr_range = '.'.join(elements[:3]) + if mask is not False: + addr_range += '/%s' % mask + return addr_range + ',' + + +def get_ports(rule): + if rule.port.all(): + result = 'port' + for port in rule.port.all(): + result += '=%s,' % port + else: + result = '' + if rule.destinationport.all(): + result += 'dstport' + for port in rule.destinationport.all(): + result += '=%s,' % port + if rule.sourceport.all(): + result += 'srcport' + for port in rule.sourceport.all(): + result += '=%s,' % port + return result + + +def create_junos_name(rule): + name = '' + # destination + name += get_range(rule.destination) + # source + name += get_range(rule.source) + # protocols + name += get_protocols_numbers(rule.protocol.all()) + # ports + name += get_ports(rule) + frag = '' + name += frag + if name[-1] == ',': + name = name[:-1] + return name diff --git a/flowspec/models.py b/flowspec/models.py index af23a03..5f2f455 100644 --- a/flowspec/models.py +++ b/flowspec/models.py @@ -26,12 +26,14 @@ from ipaddr import * import datetime import logging from time import sleep +from junos import create_junos_name, policer_name import beanstalkc from utils.randomizer import id_generator as id_gen from tasks import * + def user_unicode_patch(self): peer = None try: @@ -66,7 +68,7 @@ THEN_CHOICES = ( ("next-term", "Next term"), ("routing-instance", "Routing Instance"), ("rate-limit", "Rate limit"), - ("sample", "Sample") + ("sample", "Sample") ) MATCH_PROTOCOL = ( @@ -93,18 +95,18 @@ ROUTE_STATES = ( ("PENDING", "PENDING"), ("OUTOFSYNC", "OUTOFSYNC"), ("INACTIVE", "INACTIVE"), - ("ADMININACTIVE", "ADMININACTIVE"), + ("ADMININACTIVE", "ADMININACTIVE"), ) def days_offset(): return datetime.date.today() + datetime.timedelta(days = settings.EXPIRATION_DAYS_OFFSET) - + class MatchPort(models.Model): port = models.CharField(max_length=24, unique=True) def __unicode__(self): return self.port class Meta: - db_table = u'match_port' + db_table = u'match_port' class MatchDscp(models.Model): dscp = models.CharField(max_length=24) @@ -122,7 +124,7 @@ class MatchProtocol(models.Model): class FragmentType(models.Model): fragmenttype = models.CharField(max_length=20, choices=FRAGMENT_CODES, verbose_name="Fragment Type") - + def __unicode__(self): return "%s" %(self.fragmenttype) @@ -130,14 +132,17 @@ class FragmentType(models.Model): class ThenAction(models.Model): 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): ret = "%s:%s" %(self.action, self.action_value) return ret.rstrip(":") + class Meta: db_table = u'then_action' ordering = ['action', 'action_value'] unique_together = ("action", "action_value") + class Route(models.Model): name = models.SlugField(max_length=128, verbose_name=_("Name")) applier = models.ForeignKey(User, blank=True, null=True) @@ -163,22 +168,22 @@ class Route(models.Model): response = models.CharField(max_length=512, blank=True, null=True, verbose_name=_("Response")) comments = models.TextField(null=True, blank=True, verbose_name=_("Comments")) - + 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. - + def clean(self, *args, **kwargs): from django.core.exceptions import ValidationError if self.destination: @@ -193,13 +198,13 @@ class Route(models.Model): self.source = address.exploded except Exception: raise ValidationError(_('Invalid network address format at Source Field')) - + def commit_add(self, *args, **kwargs): peer = self.applier.get_profile().peer.peer_tag 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) - + def commit_edit(self, *args, **kwargs): peer = self.applier.get_profile().peer.peer_tag send_message("[%s] Editing rule %s. Please wait..." %(self.applier.username, self.name), peer) @@ -222,12 +227,12 @@ class Route(models.Model): if today > self.expires: return True return False - + def check_sync(self): if not self.is_synced(): self.status = "OUTOFSYNC" self.save() - + def is_synced(self): found = False get_device = PR.Retriever() @@ -266,7 +271,7 @@ class Route(models.Model): logger.info('Source fields do not match') except: pass - + try: assert(self.fragmenttype.all()) assert(devicematch['fragment']) @@ -281,7 +286,7 @@ class Route(models.Model): logger.info('Fragment type fields do not match') except: pass - + try: assert(self.port.all()) assert(devicematch['port']) @@ -296,7 +301,7 @@ class Route(models.Model): logger.info('Port type fields do not match') except: pass - + try: assert(self.protocol.all()) assert(devicematch['protocol']) @@ -341,8 +346,8 @@ class Route(models.Model): logger.info('Source port type fields do not match') except: pass - - + + # try: # assert(self.fragmenttype) # assert(devicematch['fragment'][0]) @@ -391,10 +396,10 @@ class Route(models.Model): for statement in then_statements: if statement.action_value: ret = "%s %s %s" %(ret, statement.action, statement.action_value) - else: + else: ret = "%s %s" %(ret, statement.action) return ret - + get_then.short_description = 'Then statement' get_then.allow_tags = True # @@ -437,10 +442,10 @@ class Route(models.Model): ret = ret + "%s
Port
%s
" %(ret, dscp) ret = ret + "" return ret - + get_match.short_description = 'Match statement' get_match.allow_tags = True - + @property def applier_peer(self): try: @@ -448,7 +453,7 @@ class Route(models.Model): except: applier_peer = None return applier_peer - + @property def days_to_expire(self): if self.status not in ['EXPIRED', 'ADMININACTIVE', 'ERROR', 'INACTIVE']: @@ -460,6 +465,11 @@ class Route(models.Model): else: return False + @property + def junos_name(self): + return create_junos_name(self) + + def send_message(msg, user): # username = user.username peer = user diff --git a/flowspec/views.py b/flowspec/views.py index 95985f3..44c5f36 100644 --- a/flowspec/views.py +++ b/flowspec/views.py @@ -43,7 +43,7 @@ from django.contrib.auth import authenticate, login from django.forms.models import model_to_dict -from flowspec.forms import * +from flowspec.forms import * from flowspec.models import * from peers.models import * @@ -125,7 +125,7 @@ def group_routes_ajax(request): jresp = {} routes = build_routes_json(group_routes) jresp['aaData'] = routes - return HttpResponse(json.dumps(jresp), mimetype='application/json') + return HttpResponse(json.dumps(jresp), mimetype='application/json') @login_required @never_cache @@ -145,7 +145,7 @@ def overview_routes_ajax(request): jresp = {} routes = build_routes_json(group_routes) jresp['aaData'] = routes - return HttpResponse(json.dumps(jresp), mimetype='application/json') + return HttpResponse(json.dumps(jresp), mimetype='application/json') def build_routes_json(groutes): routes = [] @@ -153,7 +153,10 @@ def build_routes_json(groutes): rd = {} rd['id'] = r.pk rd['name'] = r.name - rd['comments'] = r.comments + if not r.comments: + rd['comments'] = 'Not Any' + else: + rd['comments'] = r.comments rd['match'] = r.get_match() rd['then'] = r.get_then() rd['status'] = r.status @@ -340,7 +343,7 @@ def delete_route(request, route_slug): {"route": route, "address": requesters_address, "action": "removal", "url": admin_url}) user_mail = "%s" %route.applier.email user_mail = user_mail.split(';') - send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username), + send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username), mail_body, settings.SERVER_EMAIL, user_mail, get_peer_techc_mails(route.applier)) d = { 'clientip' : requesters_address, 'user' : route.applier.username } @@ -382,7 +385,7 @@ def user_login(request): mail = lookupShibAttr(settings.SHIB_MAIL, request.META) entitlement = lookupShibAttr(settings.SHIB_ENTITLEMENT, request.META) #organization = request.META['HTTP_SHIB_HOMEORGANIZATION'] - + if settings.SHIB_AUTH_ENTITLEMENT in entitlement.split(";"): has_entitlement = True if not has_entitlement: @@ -414,7 +417,7 @@ def user_login(request): except: user_exists = False user = authenticate(username=username, firstname=firstname, lastname=lastname, mail=mail, authsource='shibboleth') - + if user is not None: try: peer = user.get_profile().peer @@ -448,8 +451,8 @@ def user_login(request): def user_activation_notify(user): current_site = Site.objects.get_current() peer = user.get_profile().peer - - + + # Email subject *must not* contain newlines # TechCs will be notified about new users. # Platform admins will activate the users. @@ -464,10 +467,10 @@ def user_activation_notify(user): 'user': user }) if settings.NOTIFY_ADMIN_MAILS: admin_mails = settings.NOTIFY_ADMIN_MAILS - send_new_mail(settings.EMAIL_SUBJECT_PREFIX + subject, + send_new_mail(settings.EMAIL_SUBJECT_PREFIX + subject, message, settings.SERVER_EMAIL, admin_mails, []) - + # Mail to domain techCs plus platform admins (no activation hash sent) subject = render_to_string('registration/activation_email_peer_notify_subject.txt', { 'site': current_site, @@ -476,7 +479,7 @@ def user_activation_notify(user): message = render_to_string('registration/activation_email_peer_notify.txt', { 'user': user, 'peer': peer }) - send_new_mail(settings.EMAIL_SUBJECT_PREFIX + subject, + send_new_mail(settings.EMAIL_SUBJECT_PREFIX + subject, message, settings.SERVER_EMAIL, get_peer_techc_mails(user), []) @@ -534,7 +537,7 @@ def selectinst(request): context_instance=RequestContext(request)) except UserProfile.DoesNotExist: pass - + form = UserProfileForm(request_data) if form.is_valid(): userprofile = form.save() @@ -567,7 +570,7 @@ def overview(request): def user_logout(request): logout(request) return HttpResponseRedirect(reverse('group-routes')) - + @never_cache def load_jscript(request, file): long_polling_timeout = int(settings.POLL_SESSION_UPDATE)*1000 + 10000