Home | History | Annotate | Download | only in policyrep
      1 # Copyright 2014, 2016, 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 socket
     20 from collections import namedtuple
     21 
     22 from . import qpol
     23 from . import symbol
     24 from . import context
     25 
     26 port_range = namedtuple("port_range", ["low", "high"])
     27 
     28 
     29 def netifcon_factory(policy, name):
     30     """Factory function for creating netifcon objects."""
     31 
     32     if not isinstance(name, qpol.qpol_netifcon_t):
     33         raise NotImplementedError
     34 
     35     return Netifcon(policy, name)
     36 
     37 
     38 def nodecon_factory(policy, name):
     39     """Factory function for creating nodecon objects."""
     40 
     41     if not isinstance(name, qpol.qpol_nodecon_t):
     42         raise NotImplementedError
     43 
     44     return Nodecon(policy, name)
     45 
     46 
     47 def portcon_factory(policy, name):
     48     """Factory function for creating portcon objects."""
     49 
     50     if not isinstance(name, qpol.qpol_portcon_t):
     51         raise NotImplementedError
     52 
     53     return Portcon(policy, name)
     54 
     55 
     56 class NetContext(symbol.PolicySymbol):
     57 
     58     """Base class for in-policy network labeling rules."""
     59 
     60     def __str__(self):
     61         raise NotImplementedError
     62 
     63     @property
     64     def context(self):
     65         """The context for this statement."""
     66         return context.context_factory(self.policy, self.qpol_symbol.context(self.policy))
     67 
     68     def statement(self):
     69         return str(self)
     70 
     71 
     72 class Netifcon(NetContext):
     73 
     74     """A netifcon statement."""
     75 
     76     def __str__(self):
     77         return "netifcon {0.netif} {0.context} {0.packet}".format(self)
     78 
     79     def __hash__(self):
     80         return hash("netifcon|{0.netif}".format(self))
     81 
     82     @property
     83     def netif(self):
     84         """The network interface name."""
     85         return self.qpol_symbol.name(self.policy)
     86 
     87     @property
     88     def context(self):
     89         """The context for the interface."""
     90         return context.context_factory(self.policy, self.qpol_symbol.if_con(self.policy))
     91 
     92     @property
     93     def packet(self):
     94         """The context for the packets."""
     95         return context.context_factory(self.policy, self.qpol_symbol.msg_con(self.policy))
     96 
     97 
     98 class Nodecon(NetContext):
     99 
    100     """A nodecon statement."""
    101 
    102     def __str__(self):
    103         return "nodecon {0.address} {0.netmask} {0.context}".format(self)
    104 
    105     def __hash__(self):
    106         return hash("nodecon|{0.address}|{0.netmask}".format(self))
    107 
    108     def __eq__(self, other):
    109         # Libqpol allocates new C objects in the
    110         # nodecons iterator, so pointer comparison
    111         # in the PolicySymbol object doesn't work.
    112         try:
    113             return (self.address == other.address and
    114                     self.netmask == other.netmask and
    115                     self.context == other.context)
    116         except AttributeError:
    117             return (str(self) == str(other))
    118 
    119     @property
    120     def ip_version(self):
    121         """
    122         The IP version for the nodecon (socket.AF_INET or
    123         socket.AF_INET6).
    124         """
    125         return self.qpol_symbol.protocol(self.policy)
    126 
    127     @property
    128     def address(self):
    129         """The network address for the nodecon."""
    130         return self.qpol_symbol.addr(self.policy)
    131 
    132     @property
    133     def netmask(self):
    134         """The network mask for the nodecon."""
    135         return self.qpol_symbol.mask(self.policy)
    136 
    137 
    138 class PortconProtocol(int):
    139 
    140     """
    141     A portcon protocol type.
    142 
    143     The possible values are equivalent to protocol
    144     values in the socket module, e.g. IPPROTO_TCP, but
    145     overrides the string representation with the
    146     corresponding protocol string (udp, tcp).
    147     """
    148 
    149     _proto_to_text = {socket.IPPROTO_TCP: 'tcp',
    150                       socket.IPPROTO_UDP: 'udp'}
    151 
    152     def __str__(self):
    153         return self._proto_to_text[self]
    154 
    155 
    156 class Portcon(NetContext):
    157 
    158     """A portcon statement."""
    159 
    160     def __str__(self):
    161         low, high = self.ports
    162 
    163         if low == high:
    164             return "portcon {0.protocol} {1} {0.context}".format(self, low)
    165         else:
    166             return "portcon {0.protocol} {1}-{2} {0.context}".format(self, low, high)
    167 
    168     def __hash__(self):
    169             return hash("portcon|{0.protocol}|{1.low}|{1.high}".format(self, self.ports))
    170 
    171     @property
    172     def protocol(self):
    173         """
    174         The protocol number for the portcon (socket.IPPROTO_TCP
    175         or socket.IPPROTO_UDP).
    176         """
    177         return PortconProtocol(self.qpol_symbol.protocol(self.policy))
    178 
    179     @property
    180     def ports(self):
    181         """
    182         The port range for this portcon.
    183 
    184         Return: Tuple(low, high)
    185         low     The low port of the range.
    186         high    The high port of the range.
    187         """
    188         low = self.qpol_symbol.low_port(self.policy)
    189         high = self.qpol_symbol.high_port(self.policy)
    190         return port_range(low, high)
    191