First Matching Security Group Rule
Problem Statement
Evaluate an ordered list of firewall rules against a connection and return the decision of the first matching rule (default deny).
Background
Each rule is {"action": "allow"|"deny", "proto", "port_lo", "port_hi", "cidr"}. A connection {"proto", "port", "ip"} matches a rule if the protocol equals the rule's (or the rule proto is "*"), the port is within [port_lo, port_hi], and the ip is inside the rule's CIDR. Rules are checked in order; the first match decides. If none match, the decision is "deny".
Your Task
def evaluate(rules, conn):
Return "allow" or "deny".
Input Format
- rules (ordered list of dicts), conn (dict).
Output Format
- A string "allow" or "deny".
Sample
rules = [{"action":"allow","proto":"tcp","port_lo":443,"port_hi":443,"cidr":"0.0.0.0/0"}]
print(evaluate(rules, {"proto":"tcp","port":443,"ip":"1.2.3.4"}))
Output:
allow
Example
rules = [{"action":"allow","proto":"tcp","port_lo":443,"port_hi":443,"cidr":"0.0.0.0/0"}]
print(evaluate(rules, {"proto":"tcp","port":443,"ip":"1.2.3.4"}))allow
- Protocol Check: The connection protocol is
tcpand the rule's protocol istcp. Since they match (and the rule is not a wildcard*), the protocol condition is satisfied. - Port Range Check: The connection port is . The rule specifies a range from
port_lo= toport_hi= . We verify if , which is true, so the port condition is satisfied. - CIDR Check: The connection IP is
1.2.3.4and the rule's CIDR is0.0.0.0/0. A prefix length of means the subnet mask is (all zeros). Any IP address matches a/0CIDR because the network portion is empty. Thus, the IP condition is satisfied. - Rule Decision: Since all three conditions (protocol, port, and IP) match the first rule in the list, the evaluation stops immediately. The action associated with this rule is
"allow". - The final output is
allow
Constraints
- Proto matches if equal or the rule proto is
"*". - Port must be within
[port_lo, port_hi]; ip within the rule CIDR. - First matching rule wins; default
"deny".