Skip to content

Conversation

jjhwan-h
Copy link

@jjhwan-h jjhwan-h commented Sep 10, 2025

Summary

Fixes a regression where filtered IPs (-fi) were reintroduced after aggregation (-a).

Closes #523

Fix

  • If FilterIP is set:
    • expand pCidr into its IP list with getIPList
    • skip any IPs matching FilterIP
    • add remaining IPs back as /32 (or /128) CIDRs
    • do not append the original pCidr
  • Add guard when appending IPv4-mapped addresses:
    if ip4 := firstIP.To4(); ip4 != nil &&
       !(len(firstIP) == net.IPv6len && bytes.Equal(firstIP[:12], v4Mappedv6Prefix)) {
        firstIP = append(v4Mappedv6Prefix, ip4...)
    }
    

Summary by CodeRabbit

  • New Features
    • Support filtering specific IPs during CIDR aggregation, producing adjusted ranges that exclude the specified addresses.
  • Bug Fixes
    • Correct handling of IPv4-mapped IPv6 addresses to avoid redundant mappings and ensure accurate range calculations.
  • Tests
    • Added test coverage for filtering with aggregation to validate expected output.
  • Style
    • Minor formatting cleanup for readability.

@jjhwan-h jjhwan-h force-pushed the fix/ip-filtering branch 3 times, most recently from 7894e98 to b60c971 Compare September 11, 2025 01:54
Copy link

coderabbitai bot commented Sep 11, 2025

Walkthrough

Implements a new processing path when both FilterIP and Aggregate are set: expands CIDRs to individual IP /32 or /128 CIDRs excluding filtered IPs, integrates with aggregation pipeline, and updates tests. Adds a guard in IPv4-mapped IPv6 conversion to prevent double-mapping.

Changes

Cohort / File(s) Summary
CLI processing: FilterIP + Aggregate path
cmd/mapcidr/main.go
Adds a branch that, when FilterIP and Aggregate are enabled, enumerates IPs in each CIDR, removes those in FilterIP, converts remaining to single-IP CIDRs (/32 or /128), appends to list, and conditionally adds original CIDR to ranger if Aggregate/Shuffle/Sort/AggregateApprox/Count are set. Minor formatting cleanup.
Tests for new behavior
cmd/mapcidr/main_test.go
Adds TestProcess case "FilterIPWithAggregation" validating that filtering before aggregation yields per-IP CIDRs excluding filtered addresses: input 10.0.0.0/30 with FilterIP 10.0.0.1 and Aggregate true expects 10.0.0.0/32 and 10.0.0.2/31.
IP range mapping guard
ip.go
Updates ipNetToRange to avoid remapping IPv4-mapped IPv6 addresses. Only maps IPv4 to v4-mapped IPv6 when the input isn’t already mapped; prevents double-mapping.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant CLI as mapcidr CLI
  participant P as Processor
  participant R as Ranger/Aggregator

  U->>CLI: Run with -cl CIDRs, -fi FilterIP, -a
  CLI->>P: Parse options and inputs
  alt FilterIP && Aggregate
    P->>P: getIPList(CIDR)
    P->>P: Exclude IPs in FilterIP
    loop remaining IPs
      P->>P: Build single-IP CIDR (/32 or /128)
      P->>R: Optionally add original CIDR (if Aggregate/Shuffle/Sort/Approx/Count)
    end
    R-->>CLI: Aggregated result
  else Other modes
    P->>R: Existing coalesce/sort/shuffle/approx/count path or commonFunc
    R-->>CLI: Result
  end
  CLI-->>U: Output CIDRs
  note over P,R: New path expands CIDR to IPs, filters, then aggregates
Loading
sequenceDiagram
  autonumber
  participant N as ipNetToRange
  participant IP as IP Inputs

  IP->>N: firstIP, lastIP
  alt firstIP is IPv4 and not already v4-mapped v6
    N->>N: Map to IPv4-mapped IPv6 for both ends
  else Already mapped or IPv6
    N->>N: Keep as-is
  end
  N-->>IP: Normalized range
  note over N: Guard prevents double-mapping
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks (4 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix: correctly filter IPs from CIDR during aggregation" is a concise, single-sentence summary that directly describes the PR's primary change—fixing the reintroduction of filtered IPs during aggregation—so it is clear and appropriate for a changelog-style commit/PR title.
Linked Issues Check ✅ Passed The PR implements per-CIDR expansion with per-IP filtering, re-adds remaining IPs as single-IP CIDRs, and adds a unit test ("FilterIPWithAggregation") that exercises the reported repro, which directly addresses the linked issue's objective that filtered IPs remain excluded after aggregation [#523]; the ip.go guard against double IPv4→IPv6 mapping further supports correct cross-family behavior. Given the implemented logic and the targeted test covering the repro case, the changes align with the coding objectives described in the linked issue.
Out of Scope Changes Check ✅ Passed The modifications are limited to cmd/mapcidr/main.go, its test, and ip.go (plus a minor formatting cleanup) and all changes appear directly related to fixing filtering/aggregation and preventing incorrect IPv4→IPv6 remapping; there are no unrelated files or public API changes introduced.

Poem

I hop through nets, a tidy byte delight,
Pluck one IP, leave another from sight.
Aggregates align, filtered footprints stay light—
No double-mapped shadows in the moonlit night.
With masks snug-tight, my routes are right. 🐰✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
ip.go (1)

282-285: Good guard against double IPv4-mapped IPv6 conversion; small symmetry nit

The check avoids double-mapping. For readability, consider using To4() for lastIP too.

-    firstIP = append(v4Mappedv6Prefix, ip4...)
-    lastIP = append(v4Mappedv6Prefix, lastIP...)
+    firstIP = append(v4Mappedv6Prefix, ip4...)
+    lastIP = append(v4Mappedv6Prefix, lastIP.To4()...)
cmd/mapcidr/main_test.go (1)

223-233: Regression covered — LGTM

Test asserts the exact aggregates post-filter; matches the reported issue. Consider adding an IPv6 variant and a case where FilterIP contains a CIDR to harden coverage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0770c57 and 0767afd.

📒 Files selected for processing (3)
  • cmd/mapcidr/main.go (1 hunks)
  • cmd/mapcidr/main_test.go (1 hunks)
  • ip.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/mapcidr/main_test.go (1)
cmd/mapcidr/main.go (1)
  • Options (41-69)

Comment on lines +455 to +469
if len(options.FilterIP) != 0 && options.Aggregate {
for _, ip := range getIPList([]*net.IPNet{pCidr}) {
if options.FilterIP != nil && sliceutil.Contains(options.FilterIP, ip.String()) {
continue
}
singleCIDR := &net.IPNet{
IP: ip,
Mask: net.CIDRMask(len(ip)*8, len(ip)*8),
}
allCidrs = append(allCidrs, singleCIDR)
}
if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
_ = ranger.Add(cidr)
}
} else if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid per-IP expansion; rely on RemoveCIDRs output to prevent O(N) blowups

Enumerating every IP to re-add /32 or /128 CIDRs is extremely costly for large ranges and unnecessary since the earlier RemoveCIDRs step already yields the filtered CIDRs. Append those CIDRs directly to allCidrs and aggregate.

Apply:

-            if len(options.FilterIP) != 0 && options.Aggregate {
-                for _, ip := range getIPList([]*net.IPNet{pCidr}) {
-                    if options.FilterIP != nil && sliceutil.Contains(options.FilterIP, ip.String()) {
-                        continue
-                    }
-                    singleCIDR := &net.IPNet{
-                        IP:   ip,
-                        Mask: net.CIDRMask(len(ip)*8, len(ip)*8),
-                    }
-                    allCidrs = append(allCidrs, singleCIDR)
-                }
-                if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
-                    _ = ranger.Add(cidr)
-                }
-            } else if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
-                // In case of coalesce/shuffle we need to know all the cidrs and aggregate them by calling the proper function
-                _ = ranger.Add(cidr)
-                allCidrs = append(allCidrs, pCidr)
-            } else {
-                commonFunc(cidr, outputchan)
-            }
+            if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
+                // After RemoveCIDRs above, `cidr`/`pCidr` already exclude FilterIP.
+                _ = ranger.Add(cidr)
+                allCidrs = append(allCidrs, pCidr)
+            } else {
+                commonFunc(cidr, outputchan)
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(options.FilterIP) != 0 && options.Aggregate {
for _, ip := range getIPList([]*net.IPNet{pCidr}) {
if options.FilterIP != nil && sliceutil.Contains(options.FilterIP, ip.String()) {
continue
}
singleCIDR := &net.IPNet{
IP: ip,
Mask: net.CIDRMask(len(ip)*8, len(ip)*8),
}
allCidrs = append(allCidrs, singleCIDR)
}
if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
_ = ranger.Add(cidr)
}
} else if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
// After RemoveCIDRs above, `cidr`/`pCidr` already exclude FilterIP.
_ = ranger.Add(cidr)
allCidrs = append(allCidrs, pCidr)
} else {
commonFunc(cidr, outputchan)
}
🤖 Prompt for AI Agents
In cmd/mapcidr/main.go around lines 455 to 469, the code expands each IP from a
CIDR into /32 or /128 entries which causes O(N) blowups; instead, append the
filtered CIDR (pCidr) directly to allCidrs and, when appropriate, add the
original cidr to the ranger. Remove the per-IP loop and creation of singleCIDR
entries; simply do allCidrs = append(allCidrs, pCidr) (or equivalent) and keep
the existing conditional that calls ranger.Add(cidr) when options.Aggregate ||
options.Shuffle || hasSort || options.AggregateApprox || options.Count is true
so aggregation and sorting behavior remains unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Issue] IP filtering isn't working as expected
1 participant