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# 19import logging 20from socket import IPPROTO_TCP, IPPROTO_UDP 21 22from .mixins import MatchContext 23from .query import PolicyQuery 24from .policyrep import port_range, PortconProtocol 25from .util import match_range 26 27 28class PortconQuery(MatchContext, PolicyQuery): 29 30 """ 31 Port context query. 32 33 Parameter: 34 policy The policy to query. 35 36 Keyword Parameters/Class attributes: 37 protocol The protocol to match (socket.IPPROTO_TCP for 38 TCP or socket.IPPROTO_UDP for UDP) 39 40 ports A 2-tuple of the port range to match. (Set both to 41 the same value for a single port) 42 ports_subset If true, the criteria will match if it is a subset 43 of the portcon's range. 44 ports_overlap If true, the criteria will match if it overlaps 45 any of the portcon's range. 46 ports_superset If true, the criteria will match if it is a superset 47 of the portcon's range. 48 ports_proper If true, use proper superset/subset operations. 49 No effect if not using set operations. 50 51 user The criteria to match the context's user. 52 user_regex If true, regular expression matching 53 will be used on the user. 54 55 role The criteria to match the context's role. 56 role_regex If true, regular expression matching 57 will be used on the role. 58 59 type_ The criteria to match the context's type. 60 type_regex If true, regular expression matching 61 will be used on the type. 62 63 range_ The criteria to match the context's range. 64 range_subset If true, the criteria will match if it is a subset 65 of the context's range. 66 range_overlap If true, the criteria will match if it overlaps 67 any of the context's range. 68 range_superset If true, the criteria will match if it is a superset 69 of the context's range. 70 range_proper If true, use proper superset/subset operations. 71 No effect if not using set operations. 72 """ 73 74 _protocol = None 75 _ports = None 76 ports_subset = False 77 ports_overlap = False 78 ports_superset = False 79 ports_proper = False 80 81 @property 82 def ports(self): 83 return self._ports 84 85 @ports.setter 86 def ports(self, value): 87 pending_ports = port_range(*value) 88 89 if all(pending_ports): 90 if pending_ports.low < 1 or pending_ports.high < 1: 91 raise ValueError("Port numbers must be positive: {0.low}-{0.high}". 92 format(pending_ports)) 93 94 if pending_ports.low > pending_ports.high: 95 raise ValueError( 96 "The low port must be smaller than the high port: {0.low}-{0.high}". 97 format(pending_ports)) 98 99 self._ports = pending_ports 100 else: 101 self._ports = None 102 103 @property 104 def protocol(self): 105 return self._protocol 106 107 @protocol.setter 108 def protocol(self, value): 109 if value: 110 self._protocol = PortconProtocol(value) 111 else: 112 self._protocol = None 113 114 def __init__(self, policy, **kwargs): 115 super(PortconQuery, self).__init__(policy, **kwargs) 116 self.log = logging.getLogger(__name__) 117 118 def results(self): 119 """Generator which yields all matching portcons.""" 120 self.log.info("Generating portcon results from {0.policy}".format(self)) 121 self.log.debug("Ports: {0.ports}, overlap: {0.ports_overlap}, " 122 "subset: {0.ports_subset}, superset: {0.ports_superset}, " 123 "proper: {0.ports_proper}".format(self)) 124 self.log.debug("Protocol: {0.protocol!r}".format(self)) 125 self._match_context_debug(self.log) 126 127 for portcon in self.policy.portcons(): 128 129 if self.ports and not match_range( 130 portcon.ports, 131 self.ports, 132 self.ports_subset, 133 self.ports_overlap, 134 self.ports_superset, 135 self.ports_proper): 136 continue 137 138 if self.protocol and self.protocol != portcon.protocol: 139 continue 140 141 if not self._match_context(portcon.context): 142 continue 143 144 yield portcon 145