diff options
author | Johan Lundberg <lundberg@nordu.net> | 2015-04-02 10:43:33 +0200 |
---|---|---|
committer | Johan Lundberg <lundberg@nordu.net> | 2015-04-02 10:43:33 +0200 |
commit | bd611ac59f7c4db885a2f8631ef0bcdcd1901ca0 (patch) | |
tree | e60f5333a7699cd021b33c7f5292af55b774001b /lib/policyreader.py |
Diffstat (limited to 'lib/policyreader.py')
-rw-r--r-- | lib/policyreader.py | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/lib/policyreader.py b/lib/policyreader.py new file mode 100644 index 0000000..8124221 --- /dev/null +++ b/lib/policyreader.py @@ -0,0 +1,245 @@ +#!/usr/bin/python2.4 +# +# Copyright 2011 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""Utility to provide exploration of policy definition files. + +Allows read only access of policy definition files. The library +creates a Policy object, which has filters containing terms. + +This library does no expansion on the tokens directly, such as in policy.py. + +TODO: This library is currently incomplete, and does not allow access to + every argument of a policy term. +""" + +__author__ = 'watson@google.com (Tony Watson)' + +from capirca import naming + + +class FileOpenError(Exception): + """Trouble opening a file.""" + + +class Filter(object): + """Simple filter with a name a list of terms.""" + + def __init__(self, filtername=''): + self.name = filtername + self.term = [] + + def __str__(self): + rval = [] + title = 'Filter: %s' % str(self.name) + rval.append('\n%s' % title) + rval.append('-' * len(title)) + for term in self.term: + rval.append(str(term)) + return '\n\n'.join(rval) + + +class Term(object): + """Simple term with a name a list of attributes.""" + + def __init__(self, termname=''): + self.name = termname + self.source = [] + self.destination = [] + self.sport = [] + self.dport = [] + self.action = [] + self.option = [] + self.protocol = [] + + def __str__(self): + rval = [] + rval.append(' Term: %s' % self.name) + rval.append(' Source-address:: %s' % ' '.join(self.source)) + rval.append(' Destination-address:: %s' % ' '.join(self.destination)) + rval.append(' Source-port:: %s' % ' '.join(self.sport)) + rval.append(' Destination-port:: %s' % ' '.join(self.dport)) + rval.append(' Protocol:: %s' % ' '.join(self.protocol)) + rval.append(' Option:: %s' % ' '.join(self.option)) + rval.append(' Action:: %s' % ' '.join(self.action)) + return '\n'.join(rval) + + +class Policy(object): + """Holds basic attributes of an unexpanded policy definition file.""" + + def __init__(self, filename, defs_data=None): + """Build policy object and naming definitions from provided filenames. + + Args: + filename: location of a .pol file + defs_data: location of naming definitions directory, if any + """ + self.defs = naming.Naming(defs_data) + self.filter = [] + try: + self.data = open(filename, 'r').readlines() + except IOError, error_info: + info = str(filename) + ' cannot be opened' + raise FileOpenError('%s\n%s' % (info, error_info)) + + indent = 0 + in_header = False + in_term = False + filt = Filter() + term = Term() + in_string = False + + for line in self.data: + words = line.strip().split() + quotes = len(line.split('"')) + 1 + if quotes % 2: # are we in or out of double quotes + in_string = not in_string # flip status of quote status + if not in_string: + if '{' in words: + indent += 1 + if words: + if words[0] == 'header': + in_header = True + if words[0] == 'term': + in_term = True + term = Term(words[1]) + if in_header and words[0] == 'target::': + if filt.name != words[2]: # avoid empty dupe filters due to + filt = Filter(words[2]) # multiple target header lines + if in_term: + if words[0] == 'source-address::': + term.source.extend(words[1:]) + if words[0] == 'destination-address::': + term.destination.extend(words[1:]) + if words[0] == 'source-port::': + term.sport.extend(words[1:]) + if words[0] == 'destination-port::': + term.dport.extend(words[1:]) + if words[0] == 'action::': + term.action.extend(words[1:]) + if words[0] == 'protocol::': + term.protocol.extend(words[1:]) + if words[0] == 'option::': + term.option.extend(words[1:]) + + if '}' in words: + indent -= 1 + if in_header: + self.filter.append(filt) + in_header = False + if in_term: + filt.term.append(term) + in_term = False + + def __str__(self): + return '\n'.join(str(next) for next in self.filter) + + def Matches(self, src=None, dst=None, dport=None, sport=None, + filtername=None): + """Return list of term names that match specific attributes. + + Args: + src: source ip address '12.1.1.1' + dst: destination ip address '10.1.1.1' + dport: any port/protocol combo, such as '80/tcp' or '53/udp' + sport: any port/protocol combo, such as '80/tcp' or '53/udp' + filtername: a filter name or None to search all filters + + Returns: + results: list of lists, each list is index to filter & term in the policy + + Example: + p=policyreader.Policy('policy_path', 'definitions_path') + + p.Matches(dst='209.85.216.5', dport='25/tcp') + [[0, 26]] + print p.filter[0].term[26].name + + for match in p.Matches(dst='209.85.216.5'): + print p.filter[match[0]].term[match[1]].name + + """ + rval = [] + results = [] + filter_list = [] + dport_parents = None + sport_parents = None + destination_parents = None + source_parents = None + if dport: + dport_parents = self.defs.GetServiceParents(dport) + if sport: + sport_parents = self.defs.GetServiceParents(sport) + if dst: + destination_parents = self.defs.GetIpParents(dst) + try: + destination_parents.remove('ANY') + destination_parents.remove('RESERVED') + except ValueError: + pass # ignore and continue + if src: + source_parents = self.defs.GetIpParents(src) + try: + source_parents.remove('ANY') + source_parents.remove('RESERVED') + except ValueError: + pass # ignore and continue + if not filtername: + filter_list = self.filter + else: + for idx, next in enumerate(self.filter): + if filtername == next.name: + filter_list = [self.filter[idx]] + if not filter_list: + raise 'invalid filter name: %s' % filtername + + for findex, xfilter in enumerate(filter_list): + mterms = [] + mterms.append(set()) # dport + mterms.append(set()) # sport + mterms.append(set()) # dst + mterms.append(set()) # src + for tindex, term in enumerate(xfilter.term): + if dport_parents: + for token in dport_parents: + if token in term.dport: + mterms[0].add(tindex) + else: + mterms[0].add(tindex) + if sport_parents: + for token in sport_parents: + if token in term.sport: + mterms[1].add(tindex) + else: + mterms[1].add(tindex) + if destination_parents: + for token in destination_parents: + if token in term.destination: + mterms[2].add(tindex) + else: + mterms[2].add(tindex) + if source_parents: + for token in source_parents: + if token in term.source: + mterms[3].add(tindex) + else: + mterms[3].add(tindex) + rval.append(list(mterms[0] & mterms[1] & mterms[2] & mterms[3])) + for findex, fresult in enumerate(rval): + for next in list(fresult): + results.append([findex, next]) + return results |