summaryrefslogtreecommitdiff
path: root/lib/policyreader.py
diff options
context:
space:
mode:
authorJohan Lundberg <lundberg@nordu.net>2015-04-02 10:43:33 +0200
committerJohan Lundberg <lundberg@nordu.net>2015-04-02 10:43:33 +0200
commitbd611ac59f7c4db885a2f8631ef0bcdcd1901ca0 (patch)
treee60f5333a7699cd021b33c7f5292af55b774001b /lib/policyreader.py
Diffstat (limited to 'lib/policyreader.py')
-rw-r--r--lib/policyreader.py245
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