-
Notifications
You must be signed in to change notification settings - Fork 38
Handle overlaps in except and allow CIDRs #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Can you also add a test case for this in our integration suite? |
@Pavani-Panakanti - Can you fix conflicts? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR enhances CIDR rule processing by postponing except
handling to the end of rule evaluation, inserting explicit deny‐all entries for excluded ranges, and simplifying catch‐all logic. It also updates default protocol behavior to allow any protocol, refactors key utilities, and enriches eBPF C code with detailed port‐matching comments.
- Refactor
computeMapEntriesFromEndpointRules
to aggregate rules in acidrsMap
, inherit broader‐CIDR ports, and append deny‐all entries forexcept
blocks at the end. - Remove legacy
IsCatchAllIPEntry
logic and change default protocol to ANY_IP_PROTOCOL instead of TCP; derive port ranges correctly forany_ip_protocol
. - Add explicit comments and port‐matching conditions in all four eBPF
.bpf.c
files to clarify ANY_IP_PROTOCOL and specific‐protocol logic.
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
| -------------------------------------- | -------------------------------------------------------------- |
| pkg/utils/utils_test.go | Removed TestIsCatchAllIPEntry
, updated expected IsNonHostCIDR
behavior |
| pkg/utils/utils.go | Added DENY_ALL_PROTOCOL
, removed IsCatchAllIPEntry
, updated deriveProtocolValue
and IsNonHostCIDR
|
| pkg/ebpf/c/tc.v6ingress.bpf.c | Expanded port‐matching logic comments for ANY_IP_PROTOCOL and specific protocols |
| pkg/ebpf/c/tc.v6egress.bpf.c | Same as above for egress v6 |
| pkg/ebpf/c/tc.v4ingress.bpf.c | Same detailed comments for IPv4 ingress |
| pkg/ebpf/c/tc.v4egress.bpf.c | Same detailed comments for IPv4 egress |
| pkg/ebpf/bpf_client_test.go | Removed old catch‐all test, updated helper from nonHostCIDRs
to cidrsMap
|
| pkg/ebpf/bpf_client.go | Refactored rule merging into cidrsMap
, added addDenyAllL4Entry
, removed old catch‐all path |
8613586
to
9ed76e5
Compare
9ed76e5
to
70f1c6f
Compare
pkg/ebpf/bpf_client.go
Outdated
// | ||
// How it works: | ||
// 1. A default allow-all entry is added for the node IP to ensure local node traffic is always permitted. | ||
// 2. The list of firewall rules is sorted by prefix length in descending order. This is crucial for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the sorting happens in ascending order of prefix length. I was trying to understand this while refactoring and also wrote a test for this sorting fn https://github.com/aws/aws-network-policy-agent/pull/419/files#diff-36a28a4029b0030c4806fc3502df4be1c44c2f35e54196df5cdf7c93f3448d71
pkg/ebpf/bpf_client.go
Outdated
} | ||
cidrsMap[string(firewallRule.IPCidr)] = firewallRule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I assume .IPCidr
has no collision? I am not sure if it is safe to use rule.ipcidr
as key.
pkg/ebpf/bpf_client.go
Outdated
if len(firewallRule.L4Info) == 0 { | ||
log().Debugf("No L4 specified. Add Catch all entry CIDR: %s", string(firewallRule.IPCidr)) | ||
l.addCatchAllL4Entry(&firewallRule) | ||
log().Debugf("Total L4 entries count: %d", len(firewallRule.L4Info)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think L4Info
's len is 0 if getting here.
pkg/ebpf/bpf_client.go
Outdated
|
||
if existingFirewallRuleInfo, ok := cidrsMap[string(firewallRule.IPCidr)]; ok { | ||
firewallRule.L4Info = append(firewallRule.L4Info, existingFirewallRuleInfo.L4Info...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my curiosity, these L4Info
and Except
are guaranteed not empty?
pkg/ebpf/bpf_client.go
Outdated
// Key format: Prefix length (4 bytes) followed by 4/16byte IP address | ||
firewallKey := utils.ComputeTrieKey(*firewallMapKey, l.enableIPv6) | ||
|
||
if len(value.L4Info) != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe > 1
then check to dedup?
pkg/ebpf/bpf_client.go
Outdated
for nonHostCIDR, l4Info := range nonHostCIDRs { | ||
_, cidrEntry, _ := net.ParseCIDR(nonHostCIDR) | ||
for cidr, cidrFirewallInfo := range cidrsMap { | ||
if !utils.IsNonHostCIDR(cidr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: sounds like
if utils.IsNonHostCIDR(cidr) {
...
}
will do the work?
// - If trie_val->protocol matches the packet's IP protocol (e.g., TCP or UDP), | ||
// - Then apply the same port match logic as above. | ||
|
||
if ((trie_val->protocol == ANY_IP_PROTOCOL && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are really complicate if check... Any chance we can take them out into a func? I think there is only one small different on ip->
for v4 and v6.
pkg/ebpf/bpf_client.go
Outdated
if _, ok := cidrsMap[string(exceptCidr)]; !ok { | ||
exceptFirewall := EbpfFirewallRules{ | ||
IPCidr: exceptCidr, | ||
Except: []v1alpha1.NetworkAddress{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: they can be assigned with nil.
Issue #, if available:
If there is an overlap of IPs in an allow rule and in an except block of other rule, we do not handle the merging
Description of changes:
Example:
Before this change we evaluate this as
The correct behavior for 192.168.0.0/16 should be allow on 3306 as explicit allow takes precedence and deny on rest all ports due to except
New evaluation logic - all except blocks are handled at end
Other Changes in the PR:
Testing done with multiple cases of except overlaps
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.