Skip to content

Commit 986510d

Browse files
authored
Merge pull request #689 from jjhwan-h/feat/660-support-ip-patterns
feat: add support for multi-octet and dash-based IP ranges
2 parents 1542e5c + 5bf3985 commit 986510d

File tree

4 files changed

+159
-10
lines changed

4 files changed

+159
-10
lines changed

cidr.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ func nextSubnet(network *net.IPNet, prefixLen int) (*net.IPNet, error) {
256256
// specific check.
257257
//
258258
// nolint:all
259-
func isPowerOfTwoPlusOne(x int) bool {
260-
return isPowerOfTwo(x - 1)
261-
}
259+
// func isPowerOfTwoPlusOne(x int) bool {
260+
// return isPowerOfTwo(x - 1)
261+
// }
262262

263263
// isPowerOfTwo returns if a number is a power of 2
264264
func isPowerOfTwo(x int) bool {
@@ -268,11 +268,11 @@ func isPowerOfTwo(x int) bool {
268268
// reverseIPNet reverses an ipnet slice
269269
//
270270
// nolint:all
271-
func reverseIPNet(ipnets []*net.IPNet) {
272-
for i, j := 0, len(ipnets)-1; i < j; i, j = i+1, j-1 {
273-
ipnets[i], ipnets[j] = ipnets[j], ipnets[i]
274-
}
275-
}
271+
// func reverseIPNet(ipnets []*net.IPNet) {
272+
// for i, j := 0, len(ipnets)-1; i < j; i, j = i+1, j-1 {
273+
// ipnets[i], ipnets[j] = ipnets[j], ipnets[i]
274+
// }
275+
// }
276276

277277
// IPAddresses returns all the IP addresses in a CIDR
278278
func IPAddresses(cidr string) ([]string, error) {

cmd/mapcidr/main.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,28 @@ func process(wg *sync.WaitGroup, chancidr, outputchan chan string) {
418418
}
419419

420420
for _, cidr := range cidrsToProcess {
421-
// Add IPs into ipRangeList which are passed as input. Example - "192.168.0.0-192.168.0.5"
421+
422422
if strings.Contains(cidr, "-") {
423+
// Try to parse as multi-octet range
424+
if strings.Count(cidr, ".") == 3 {
425+
ips, err := mapcidr.ExpandIPPattern(cidr)
426+
if err != nil {
427+
gologger.Fatal().Msgf("%s\n", err)
428+
}
429+
430+
for _, ip := range ips {
431+
ipCidr := ip.String() + "/32"
432+
if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
433+
_, ipnet, _ := net.ParseCIDR(ipCidr)
434+
allCidrs = append(allCidrs, ipnet)
435+
} else {
436+
commonFunc(ipCidr, outputchan)
437+
}
438+
}
439+
continue
440+
}
441+
442+
// Add IPs into ipRangeList which are passed as input. Example - "192.168.0.0-192.168.0.5"
423443
var ipRange []net.IP
424444
for _, ipstr := range strings.Split(cidr, "-") {
425445
ipRange = append(ipRange, net.ParseIP(ipstr))
@@ -451,8 +471,8 @@ func process(wg *sync.WaitGroup, chancidr, outputchan chan string) {
451471
continue
452472
}
453473

474+
// In case of coalesce/shuffle we need to know all the cidrs and aggregate them by calling the proper function
454475
if options.Aggregate || options.Shuffle || hasSort || options.AggregateApprox || options.Count {
455-
// In case of coalesce/shuffle we need to know all the cidrs and aggregate them by calling the proper function
456476
_ = ranger.Add(cidr)
457477
allCidrs = append(allCidrs, pCidr)
458478
} else {

cmd/mapcidr/main_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,67 @@ func TestProcess(t *testing.T) {
230230
Aggregate: true,
231231
},
232232
expectedOutput: []string{"10.0.0.0/32", "10.0.0.2/31"},
233+
}, {
234+
name: "MultiOctetRangeExpansion",
235+
chancidr: make(chan string),
236+
outputchan: make(chan string),
237+
options: Options{
238+
FileCidr: []string{"192.168.0-1.1-2"},
239+
},
240+
expectedOutput: []string{
241+
"192.168.0.1", "192.168.0.2",
242+
"192.168.1.1", "192.168.1.2",
243+
},
244+
},
245+
{
246+
name: "MultiOctetRangeWithFilter",
247+
chancidr: make(chan string),
248+
outputchan: make(chan string),
249+
options: Options{
250+
FileCidr: []string{"192.168.0-1.1-2"},
251+
FilterIP: []string{"192.168.1.1"},
252+
},
253+
expectedOutput: []string{
254+
"192.168.0.1", "192.168.0.2",
255+
"192.168.1.2",
256+
},
257+
},
258+
{
259+
name: "MultiOctetRangeAggregate",
260+
chancidr: make(chan string),
261+
outputchan: make(chan string),
262+
options: Options{
263+
FileCidr: []string{"10.0-1.0-1.0-1"},
264+
Aggregate: true,
265+
},
266+
expectedOutput: []string{
267+
"10.0.0.0/31", "10.0.1.0/31",
268+
"10.1.0.0/31", "10.1.1.0/31",
269+
},
270+
},
271+
{
272+
name: "MultiOctetRangeSortAscending",
273+
chancidr: make(chan string),
274+
outputchan: make(chan string),
275+
options: Options{
276+
FileCidr: []string{"10.0.0-0.2-3"},
277+
SortAscending: true,
278+
},
279+
expectedOutput: []string{
280+
"10.0.0.2", "10.0.0.3",
281+
},
282+
},
283+
{
284+
name: "MultiOctetRangeSortDescending",
285+
chancidr: make(chan string),
286+
outputchan: make(chan string),
287+
options: Options{
288+
FileCidr: []string{"10.0.1-2.1"},
289+
SortDescending: true,
290+
},
291+
expectedOutput: []string{
292+
"10.0.2.1", "10.0.1.1",
293+
},
233294
},
234295
}
235296
var wg sync.WaitGroup

ip.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,3 +1211,71 @@ func IpRangeToCIDR(start, end string) ([]string, error) {
12111211
}
12121212
return cidr, nil
12131213
}
1214+
1215+
/*
1216+
ExpandIPPattern expands an IPv4 pattern string into a list of net.IP addresses.
1217+
The pattern must be in the form of four octets separated by dots (a.b.c.d).
1218+
*/
1219+
func ExpandIPPattern(pattern string) ([]net.IP, error) {
1220+
parts := strings.Split(pattern, ".")
1221+
if len(parts) != 4 {
1222+
return nil, fmt.Errorf("invalid IP pattern: %s", pattern)
1223+
}
1224+
1225+
var octets [][]int
1226+
for _, part := range parts {
1227+
if strings.Contains(part, "-") {
1228+
bounds := strings.Split(part, "-")
1229+
if len(bounds) != 2 {
1230+
return nil, fmt.Errorf("invalid range in %s", part)
1231+
}
1232+
1233+
start, err1 := strconv.Atoi(bounds[0])
1234+
end, err2 := strconv.Atoi(bounds[1])
1235+
1236+
if err1 != nil || err2 != nil || start > end {
1237+
return nil, fmt.Errorf("invalid range: %s", part)
1238+
}
1239+
1240+
var nums []int
1241+
for i := start; i <= end; i++ {
1242+
nums = append(nums, i)
1243+
}
1244+
octets = append(octets, nums)
1245+
1246+
} else {
1247+
v, err := strconv.Atoi(part)
1248+
if err != nil {
1249+
return nil, fmt.Errorf("invalid octet: %s", part)
1250+
}
1251+
1252+
octets = append(octets, []int{v})
1253+
}
1254+
}
1255+
1256+
var ips []net.IP
1257+
for _, o1 := range octets[0] {
1258+
if o1 < 0 || o1 > 255 {
1259+
return nil, fmt.Errorf("invalid octet value: %d", o1)
1260+
}
1261+
for _, o2 := range octets[1] {
1262+
if o2 < 0 || o2 > 255 {
1263+
return nil, fmt.Errorf("invalid octet value: %d", o2)
1264+
}
1265+
for _, o3 := range octets[2] {
1266+
if o3 < 0 || o3 > 255 {
1267+
return nil, fmt.Errorf("invalid octet value: %d", o3)
1268+
}
1269+
for _, o4 := range octets[3] {
1270+
if o4 < 0 || o4 > 255 {
1271+
return nil, fmt.Errorf("invalid octet value: %d", o4)
1272+
}
1273+
ip := net.IPv4(byte(o1), byte(o2), byte(o3), byte(o4))
1274+
ips = append(ips, ip)
1275+
}
1276+
}
1277+
}
1278+
}
1279+
1280+
return ips, nil
1281+
}

0 commit comments

Comments
 (0)