Home | History | Annotate | Download | only in setools
      1 # Copyright 2014-2015, Tresys Technology, LLC
      2 #
      3 # This file is part of SETools.
      4 #
      5 # SETools is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Lesser General Public License as
      7 # published by the Free Software Foundation, either version 2.1 of
      8 # the License, or (at your option) any later version.
      9 #
     10 # SETools is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Lesser General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Lesser General Public
     16 # License along with SETools.  If not, see
     17 # <http://www.gnu.org/licenses/>.
     18 #
     19 import logging
     20 from socket import IPPROTO_TCP, IPPROTO_UDP
     21 
     22 from . import contextquery
     23 from .policyrep.netcontext import port_range
     24 
     25 
     26 class PortconQuery(contextquery.ContextQuery):
     27 
     28     """
     29     Port context query.
     30 
     31     Parameter:
     32     policy          The policy to query.
     33 
     34     Keyword Parameters/Class attributes:
     35     protocol        The protocol to match (socket.IPPROTO_TCP for
     36                     TCP or socket.IPPROTO_UDP for UDP)
     37 
     38     ports           A 2-tuple of the port range to match. (Set both to
     39                     the same value for a single port)
     40     ports_subset    If true, the criteria will match if it is a subset
     41                     of the portcon's range.
     42     ports_overlap   If true, the criteria will match if it overlaps
     43                     any of the portcon's range.
     44     ports_superset  If true, the criteria will match if it is a superset
     45                     of the portcon's range.
     46     ports_proper    If true, use proper superset/subset operations.
     47                     No effect if not using set operations.
     48 
     49     user            The criteria to match the context's user.
     50     user_regex      If true, regular expression matching
     51                     will be used on the user.
     52 
     53     role            The criteria to match the context's role.
     54     role_regex      If true, regular expression matching
     55                     will be used on the role.
     56 
     57     type_           The criteria to match the context's type.
     58     type_regex      If true, regular expression matching
     59                     will be used on the type.
     60 
     61     range_          The criteria to match the context's range.
     62     range_subset    If true, the criteria will match if it is a subset
     63                     of the context's range.
     64     range_overlap   If true, the criteria will match if it overlaps
     65                     any of the context's range.
     66     range_superset  If true, the criteria will match if it is a superset
     67                     of the context's range.
     68     range_proper    If true, use proper superset/subset operations.
     69                     No effect if not using set operations.
     70     """
     71 
     72     _protocol = None
     73     _ports = None
     74     ports_subset = False
     75     ports_overlap = False
     76     ports_superset = False
     77     ports_proper = False
     78 
     79     @property
     80     def ports(self):
     81         return self._ports
     82 
     83     @ports.setter
     84     def ports(self, value):
     85         pending_ports = port_range(*value)
     86 
     87         if all(pending_ports):
     88             if pending_ports.low < 1 or pending_ports.high < 1:
     89                 raise ValueError("Port numbers must be positive: {0.low}-{0.high}".
     90                                  format(pending_ports))
     91 
     92             if pending_ports.low > pending_ports.high:
     93                 raise ValueError(
     94                     "The low port must be smaller than the high port: {0.low}-{0.high}".
     95                     format(pending_ports))
     96 
     97             self._ports = pending_ports
     98         else:
     99             self._ports = None
    100 
    101     @property
    102     def protocol(self):
    103         return self._protocol
    104 
    105     @protocol.setter
    106     def protocol(self, value):
    107         if value:
    108             if not (value == IPPROTO_TCP or value == IPPROTO_UDP):
    109                 raise ValueError(
    110                     "The protocol must be {0} for TCP or {1} for UDP.".
    111                     format(IPPROTO_TCP, IPPROTO_UDP))
    112 
    113             self._protocol = value
    114         else:
    115             self._protocol = None
    116 
    117     def results(self):
    118         """Generator which yields all matching portcons."""
    119         self.log.info("Generating results from {0.policy}".format(self))
    120         self.log.debug("Ports: {0.ports}, overlap: {0.ports_overlap}, "
    121                        "subset: {0.ports_subset}, superset: {0.ports_superset}, "
    122                        "proper: {0.ports_proper}".format(self))
    123         self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self))
    124         self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self))
    125         self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self))
    126         self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, "
    127                        "superset: {0.range_superset}, proper: {0.range_proper}".format(self))
    128 
    129         for portcon in self.policy.portcons():
    130 
    131             if self.ports and not self._match_range(
    132                     portcon.ports,
    133                     self.ports,
    134                     self.ports_subset,
    135                     self.ports_overlap,
    136                     self.ports_superset,
    137                     self.ports_proper):
    138                 continue
    139 
    140             if self.protocol and self.protocol != portcon.protocol:
    141                 continue
    142 
    143             if not self._match_context(portcon.context):
    144                 continue
    145 
    146             yield portcon
    147