Evaluate Security Group Rules
Problem Statement
A security group is a stateful, allow-only firewall: there are no deny rules, and anything not explicitly permitted is dropped. Given a group's inbound rules and a batch of attempted connections, decide each one.
Background
Evaluation is a pure OR over the rules — a connection is allowed if any rule matches, denied otherwise. Default-deny is what makes a security group safe: forgetting a rule closes a port, it never opens one.
A rule matches a connection when all three hold:
- Protocol: rule["protocol"] == conn["protocol"], or the rule's protocol is "-1" meaning all protocols.
- Port: rule["from_port"] <= conn["port"] <= rule["to_port"] — the range is inclusive at both ends. A rule for "-1" is given as from_port: 0, to_port: 65535.
- Source: the connection's source IP falls inside the rule's CIDR. 0.0.0.0/0 is the whole internet; a /32 is one host.
Rules are unordered, and order makes no difference to the outcome.
Your Task
Implement:
def evaluate_rules(rules, connections):
Return a list of "ALLOW" / "DENY" strings, one per connection, in input order.
Input Format
- rules: list of dicts with "protocol" ("tcp", "udp", "icmp" or "-1"), "from_port", "to_port", "cidr".
- connections: list of dicts with "protocol", "port", "source".
Output Format
- A list of strings, each "ALLOW" or "DENY".
Sample
rules = [{"protocol": "tcp", "from_port": 22, "to_port": 22, "cidr": "10.0.0.0/16"},
{"protocol": "tcp", "from_port": 8000, "to_port": 8010, "cidr": "0.0.0.0/0"}]
conns = [{"protocol": "tcp", "port": 22, "source": "10.0.3.4"},
{"protocol": "tcp", "port": 22, "source": "203.0.113.9"},
{"protocol": "tcp", "port": 8010, "source": "203.0.113.9"}]
print(evaluate_rules(rules, conns))
Output:
['ALLOW', 'DENY', 'ALLOW']
SSH is open only to the VPC, so the public source is dropped; port 8010 is the inclusive upper end of the serving range and is open to everyone.
Example:
rules = [{"protocol": "tcp", "from_port": 22, "to_port": 22, "cidr": "10.0.0.0/16"}, {"protocol": "tcp", "from_port": 8000, "to_port": 8010, "cidr": "0.0.0.0/0"}]
conns = [{"protocol": "tcp", "port": 22, "source": "10.0.3.4"}, {"protocol": "tcp", "port": 22, "source": "203.0.113.9"}, {"protocol": "tcp", "port": 8010, "source": "203.0.113.9"}]
print(evaluate_rules(rules, conns))['ALLOW', 'DENY', 'ALLOW']
The first connection matches the SSH rule on all three axes. The second is the same port and protocol but its source is outside 10.0.0.0/16, and since no other rule covers port 22 it is denied by default. The third hits the inclusive upper bound of the 8000-8010 range from a source inside 0.0.0.0/0, so it is allowed.
Constraints:
- 0 <= len(rules) <= 100, 0 <= len(connections) <= 100
- Security groups are allow-only: a connection matching no rule is DENY
- Port ranges are inclusive at both ends
- Protocol
"-1"matches any protocol and is given with ports 0-65535 - Source matching is by CIDR containment;
0.0.0.0/0matches every address - Return one verdict per connection, in input order
1. Background Knowledge
Security Groups function as virtual firewalls in cloud networking. Unlike traditional firewalls that often use a "default allow" or complex deny-lists, security groups are stateful and allow-only. This means traffic is blocked by default unless a specific rule explicitly permits it. Understanding this "default-deny" posture is crucial: if no rule matches a connection attempt, the result is automatically DENY.
The core of this problem lies in CIDR (Classless Inter-Domain Routing) notation and IP address arithmetic. A CIDR block like 10.0.0.0/16 defines a range of IP addresses. The /16 indicates that the first 16 bits of the IP address are fixed (the network prefix), while the remaining 16 bits can vary (the host portion). To check if an IP belongs to a CIDR block, you must convert both the IP address and the CIDR prefix into their integer representations and apply a bitwise mask.
Additionally, you must handle protocol wildcards. In many cloud providers, the protocol -1 signifies "all protocols." Similarly, a port range of 0 to 65535 covers all possible TCP/UDP ports. Your logic must treat these wildcards as universal matchers for their respective fields, ensuring that a rule with protocol: "-1" matches a connection with protocol: "tcp".
2. Algorithm Approach
The problem requires evaluating a list of connections against a list of rules. Since the order of rules does not matter (it is a pure OR operation), the most straightforward approach is Iterative Matching.
For each connection in the input list:
- Iterate through every rule in the rules list.
- Check if the connection satisfies all three conditions of the rule: Protocol, Port Range, and Source CIDR.
- If any rule matches all three conditions, mark the connection as ALLOW and stop checking further rules for that connection (short-circuit evaluation).
- If the loop completes without finding a match, mark the connection as DENY.
This approach leverages the short-circuit nature of logical OR operations. You do not need to check all rules if one already grants access.
3. Step-by-Step Strategy
Continue the full explanation
You're reading the free preview. Unlock the complete walkthrough, the code editor, test runner and reference solution with Premium.
Editor locked
The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.