Skip to content

Commit 6df9d0d

Browse files
committed
Support CIDR notation in input files (e.g. 1.2.3.0/24)
Automatically expands CIDR ranges to individual host IPs. Warns when total count exceeds 100K.
1 parent f44dd09 commit 6df9d0d

1 file changed

Lines changed: 44 additions & 1 deletion

File tree

internal/scanner/input.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func loadText(path string) ([]string, error) {
2424
defer f.Close()
2525

2626
var entries []string
27-
var skipped int
27+
var skipped, cidrCount int
2828
sc := bufio.NewScanner(f)
2929
for sc.Scan() {
3030
line := strings.TrimSpace(sc.Text())
@@ -36,6 +36,15 @@ func loadText(path string) ([]string, error) {
3636
entries = append(entries, line)
3737
continue
3838
}
39+
// Try CIDR notation (e.g. 1.2.3.0/24)
40+
if strings.Contains(line, "/") {
41+
ips, err := expandCIDR(line)
42+
if err == nil {
43+
cidrCount++
44+
entries = append(entries, ips...)
45+
continue
46+
}
47+
}
3948
ip := line
4049
// Strip optional :port suffix
4150
if host, _, err := net.SplitHostPort(line); err == nil {
@@ -50,12 +59,46 @@ func loadText(path string) ([]string, error) {
5059
if err := sc.Err(); err != nil {
5160
return nil, err
5261
}
62+
if cidrCount > 0 {
63+
fmt.Fprintf(os.Stderr, "input: expanded %d CIDR ranges -> %d IPs\n", cidrCount, len(entries))
64+
}
5365
if skipped > 0 {
5466
fmt.Fprintf(os.Stderr, "input: skipped %d invalid entries\n", skipped)
5567
}
68+
if len(entries) > 100000 {
69+
fmt.Fprintf(os.Stderr, "warning: %d IPs is a lot — consider using smaller CIDR ranges or filtering first\n", len(entries))
70+
}
5671
return entries, nil
5772
}
5873

74+
func expandCIDR(cidr string) ([]string, error) {
75+
ip, ipnet, err := net.ParseCIDR(cidr)
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
var ips []string
81+
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); incIP(ip) {
82+
ips = append(ips, ip.String())
83+
}
84+
85+
// Remove network and broadcast addresses for IPv4 ranges > /31
86+
if len(ips) > 2 {
87+
ips = ips[1 : len(ips)-1]
88+
}
89+
90+
return ips, nil
91+
}
92+
93+
func incIP(ip net.IP) {
94+
for j := len(ip) - 1; j >= 0; j-- {
95+
ip[j]++
96+
if ip[j] > 0 {
97+
break
98+
}
99+
}
100+
}
101+
59102
func loadJSON(path string, includeFailed bool) ([]string, error) {
60103
data, err := os.ReadFile(path)
61104
if err != nil {

0 commit comments

Comments
 (0)