#2205 - Fixed ACLRule.is_permitted function by returning a bool that indicates whether the rule was matched or not to allow the AccessControlList to know whether to pay attention to the rule or not when it's iterating over them.

This commit is contained in:
Chris McCarthy
2024-02-10 21:32:13 +00:00
parent 58af58810d
commit a8c1e2b9d9
2 changed files with 73 additions and 39 deletions

View File

@@ -356,7 +356,7 @@ This function showcases each rule in an ACL, outlining its:
- **Src IP and Dst IP**: Source and destination IP addresses. - **Src IP and Dst IP**: Source and destination IP addresses.
- **Src Wildcard and Dst** Wildcard: Wildcard masks for source and destination IP ranges. - **Src Wildcard and Dst** Wildcard: Wildcard masks for source and destination IP ranges.
- **Src Port and Dst Port**: Source and destination ports. - **Src Port and Dst Port**: Source and destination ports.
- **Hit Count**: The number of times the rule has been matched by traffic. - **Matched**: The number of times the rule has been matched by traffic.
Example Output: Example Output:
@@ -365,7 +365,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - External Inbound Access Control List | | firewall_1 - External Inbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 |
| 23 | PERMIT | ICMP | ANY | ANY | ANY | ANY | ANY | ANY | 0 | | 23 | PERMIT | ICMP | ANY | ANY | ANY | ANY | ANY | ANY | 0 |
@@ -375,7 +375,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - External Outbound Access Control List | | firewall_1 - External Outbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 |
| 23 | PERMIT | ICMP | ANY | ANY | ANY | ANY | ANY | ANY | 0 | | 23 | PERMIT | ICMP | ANY | ANY | ANY | ANY | ANY | ANY | 0 |
@@ -385,7 +385,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - Internal Inbound Access Control List | | firewall_1 - Internal Inbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 | | 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 |
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 |
@@ -396,7 +396,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - Internal Outbound Access Control List | | firewall_1 - Internal Outbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 | | 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 |
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 |
@@ -407,7 +407,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - DMZ Inbound Access Control List | | firewall_1 - DMZ Inbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 | | 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 |
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 0 |
@@ -418,7 +418,7 @@ Example Output:
+---------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------+
| firewall_1 - DMZ Outbound Access Control List | | firewall_1 - DMZ Outbound Access Control List |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Hit Count | | Index | Action | Protocol | Src IP | Src Wildcard | Src Port | Dst IP | Dst Wildcard | Dst Port | Matched |
+-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+ +-------+--------+----------+--------+--------------+-----------+--------+--------------+-----------+-----------+
| 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 | | 1 | PERMIT | ANY | ANY | ANY | 123 (NTP) | ANY | ANY | 123 (NTP) | 1 |
| 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 | | 22 | PERMIT | ANY | ANY | ANY | 219 (ARP) | ANY | ANY | 219 (ARP) | 1 |

View File

@@ -123,7 +123,7 @@ class ACLRule(SimComponent):
dst_wildcard_mask: Optional[IPV4Address] = None dst_wildcard_mask: Optional[IPV4Address] = None
src_port: Optional[Port] = None src_port: Optional[Port] = None
dst_port: Optional[Port] = None dst_port: Optional[Port] = None
hit_count: int = 0 match_count: int = 0
def __str__(self) -> str: def __str__(self) -> str:
rule_strings = [] rule_strings = []
@@ -154,10 +154,10 @@ class ACLRule(SimComponent):
state["src_port"] = self.src_port.name if self.src_port else None state["src_port"] = self.src_port.name if self.src_port else None
state["dst_ip_address"] = str(self.dst_ip_address) if self.dst_ip_address else None state["dst_ip_address"] = str(self.dst_ip_address) if self.dst_ip_address else None
state["dst_port"] = self.dst_port.name if self.dst_port else None state["dst_port"] = self.dst_port.name if self.dst_port else None
state["hit_count"] = self.hit_count state["match_count"] = self.match_count
return state return state
def permit_frame_check(self, frame: Frame) -> bool: def permit_frame_check(self, frame: Frame) -> Tuple[bool, bool]:
""" """
Evaluates whether a given network frame should be permitted or denied based on this ACL rule. Evaluates whether a given network frame should be permitted or denied based on this ACL rule.
@@ -177,9 +177,13 @@ class ACLRule(SimComponent):
4. The frame is permitted if it matches all specified criteria and the rule's action is PERMIT. Conversely, it 4. The frame is permitted if it matches all specified criteria and the rule's action is PERMIT. Conversely, it
is not permitted if any criterion does not match or if the rule's action is DENY. is not permitted if any criterion does not match or if the rule's action is DENY.
:param frame (Frame): The network frame to be evaluated. :param frame: The network frame to be evaluated.
:return: True if the frame is permitted by this ACL rule, False otherwise. :return: A tuple containing two boolean values: The first indicates if the frame is permitted by this rule (
True if permitted, otherwise False). The second indicates if the frame matches the rule's criteria (True
if it matches, otherwise False).
""" """
permitted = False
frame_matches_rule = False
protocol_matches = self.protocol == frame.ip.protocol if self.protocol else True protocol_matches = self.protocol == frame.ip.protocol if self.protocol else True
src_ip_matches = self.src_ip_address is None # Assume match if no specific src IP is defined src_ip_matches = self.src_ip_address is None # Assume match if no specific src IP is defined
@@ -222,10 +226,10 @@ class ACLRule(SimComponent):
# The frame is permitted if all conditions are met # The frame is permitted if all conditions are met
if protocol_matches and src_ip_matches and dst_ip_matches and src_port_matches and dst_port_matches: if protocol_matches and src_ip_matches and dst_ip_matches and src_port_matches and dst_port_matches:
return self.action == ACLAction.PERMIT frame_matches_rule = True
else: permitted = self.action == ACLAction.PERMIT
# If any condition is not met, the decision depends on the rule action
return False return permitted, frame_matches_rule
class AccessControlList(SimComponent): class AccessControlList(SimComponent):
@@ -336,6 +340,7 @@ class AccessControlList(SimComponent):
) )
def _init_request_manager(self) -> RequestManager: def _init_request_manager(self) -> RequestManager:
# TODO: Add src and dst wildcard masks as positional args in this request.
rm = super()._init_request_manager() rm = super()._init_request_manager()
# When the request reaches this action, it should now contain solely positional args for the 'add_rule' action. # When the request reaches this action, it should now contain solely positional args for the 'add_rule' action.
@@ -351,13 +356,13 @@ class AccessControlList(SimComponent):
"add_rule", "add_rule",
RequestType( RequestType(
func=lambda request, context: self.add_rule( func=lambda request, context: self.add_rule(
ACLAction[request[0]], action=ACLAction[request[0]],
None if request[1] == "ALL" else IPProtocol[request[1]], protocol=None if request[1] == "ALL" else IPProtocol[request[1]],
None if request[2] == "ALL" else IPv4Address(request[2]), src_ip_address=None if request[2] == "ALL" else IPv4Address(request[2]),
None if request[3] == "ALL" else Port[request[3]], src_port=None if request[3] == "ALL" else Port[request[3]],
None if request[4] == "ALL" else IPv4Address(request[4]), dst_ip_address=None if request[4] == "ALL" else IPv4Address(request[4]),
None if request[5] == "ALL" else Port[request[5]], dst_port=None if request[5] == "ALL" else Port[request[5]],
int(request[6]), position=int(request[6]),
) )
), ),
) )
@@ -410,18 +415,47 @@ class AccessControlList(SimComponent):
position: int = 0, position: int = 0,
) -> None: ) -> None:
""" """
Add a new ACL rule. Adds a new ACL rule to control network traffic based on specified criteria.
:param ACLAction action: Action to be performed (Permit/Deny). This method allows defining rules that specify whether to permit or deny traffic with particular
:param protocol: Network protocol. Optional, default is None. characteristics, including source and destination IP addresses, ports, and protocols. Wildcard masks can be
:param src_ip_address: Source IP address. Optional, default is None. used to specify a range of IP addresses, allowing for broader rule application. If specifying a dedicated IP
:param src_wildcard_mask: Source IP wildcard mask. Optional, default is None. address without needing a range, the wildcard mask can be omitted.
:param src_port: Source port number. Optional, default is None.
:param dst_ip_address: Destination IP address. Optional, default is None. Example:
:param dst_wildcard_mask: Destination IP wildcard mask. Optional, default is None. >>> # To block all traffic except SSH from a specific IP range to a server:
:param dst_port: Destination port number. Optional, default is None. >>> router = Router("router")
:param int position: Position in the ACL list to insert the rule. Optional, default is 1. >>> router.add_rule(
:raises ValueError: When the position is out of bounds. ... action=ACLAction.DENY,
... protocol=IPProtocol.TCP,
... src_ip_address="192.168.1.0",
... src_wildcard_mask="0.0.0.255",
... dst_ip_address="10.10.10.5",
... dst_port=Port.SSH,
... position=5
... )
>>> # This permits SSH traffic from the 192.168.1.0/24 subnet to the 10.10.10.5 server.
>>>
>>> # Then if we want to allow a specific IP address from this subnet to SSH into the server
>>> router.add_rule(
... action=ACLAction.PERMIT,
... protocol=IPProtocol.TCP,
... src_ip_address="192.168.1.25",
... dst_ip_address="10.10.10.5",
... dst_port=Port.SSH,
... position=4
... )
:param action: The action to take (Permit/Deny) when the rule matches traffic.
:param protocol: The network protocol (TCP/UDP/ICMP) to match. If None, matches any protocol.
:param src_ip_address: The source IP address to match. If None, matches any source IP.
:param src_wildcard_mask: Specifies a wildcard mask for the source IP. Use for IP ranges.
:param dst_ip_address: The destination IP address to match. If None, matches any destination IP.
:param dst_wildcard_mask: Specifies a wildcard mask for the destination IP. Use for IP ranges.
:param src_port: The source port to match. If None, matches any source port.
:param dst_port: The destination port to match. If None, matches any destination port.
:param int position: The position in the ACL list to insert this rule. Defaults is position 0 right at the top.
:raises ValueError: If the position is out of bounds.
""" """
if 0 <= position < self.max_acl_rules: if 0 <= position < self.max_acl_rules:
if self._acl[position]: if self._acl[position]:
@@ -461,15 +495,15 @@ class AccessControlList(SimComponent):
if not _rule: if not _rule:
continue continue
if _rule.permit_frame_check(frame): permitted, rule_match = _rule.permit_frame_check(frame)
permitted = True if rule_match:
rule = _rule rule = _rule
break break
if not rule: if not rule:
permitted = self.implicit_action == ACLAction.PERMIT permitted = self.implicit_action == ACLAction.PERMIT
rule = self.implicit_rule rule = self.implicit_rule
rule.hit_count += 1 rule.match_count += 1
return permitted, rule return permitted, rule
@@ -528,7 +562,7 @@ class AccessControlList(SimComponent):
"Dst IP", "Dst IP",
"Dst Wildcard", "Dst Wildcard",
"Dst Port", "Dst Port",
"Hit Count", "Matched",
] ]
) )
if markdown: if markdown:
@@ -549,7 +583,7 @@ class AccessControlList(SimComponent):
rule.dst_ip_address if rule.dst_ip_address else "ANY", rule.dst_ip_address if rule.dst_ip_address else "ANY",
rule.dst_wildcard_mask if rule.dst_wildcard_mask else "ANY", rule.dst_wildcard_mask if rule.dst_wildcard_mask else "ANY",
f"{rule.dst_port.value} ({rule.dst_port.name})" if rule.dst_port else "ANY", f"{rule.dst_port.value} ({rule.dst_port.name})" if rule.dst_port else "ANY",
rule.hit_count, rule.match_count,
] ]
) )
print(table) print(table)