Skip to content

Commit 4357816

Browse files
authored
Merge pull request #11 from Netnod/SubsetCIDRs
SubsetCIDRs
2 parents 7b73ab0 + 1564cad commit 4357816

File tree

8 files changed

+785
-22
lines changed

8 files changed

+785
-22
lines changed

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ This is a fork from [EvilSuperstars/go-cidrman](https://github.com/EvilSuperstar
88

99
## Background
1010

11-
*Note:* This project uses [Go Modules](https://blog.golang.org/using-go-modules) making it safe to work with it outside of
12-
your existing [GOPATH](http://golang.org/doc/code.html#GOPATH). The instructions that follow assume a directory in your
13-
home directory outside of the standard GOPATH (i.e `$HOME/git/GitHub/Netnod/go-cidrman/`).
11+
*Note:* This project uses [Go Modules](https://blog.golang.org/using-go-modules) making it
12+
safe to work with it outside of your existing [GOPATH](http://golang.org/doc/code.html#GOPATH).
13+
The instructions that follow assume a directory in your home directory
14+
outside of the standard GOPATH (i.e `$HOME/git/GitHub/Netnod/go-cidrman/`).
1415

1516
# Build instructions
1617

@@ -51,7 +52,8 @@ $ make clean
5152
## Findings about the original project
5253

5354
A lot of work was done in the `ipv6-experimental` branch in February and December 2017.
54-
In June 2019, some of the *metafiles* in the `master` branch were created or updated, without changes to the code itself.
55+
In June 2019, some of the *metafiles* in the `master` branch were created or updated,
56+
without changes to the code itself.
5557

5658
## Where are we now?
5759

@@ -64,8 +66,11 @@ In April 2022, a `merge-experimental` branch was temporarily used to merge the o
6466
together with the IPv6 support developed in this fork.
6567
With IPv6 support now in `main`, the `ipv6-experimental` branch was removed as it's no longer relevant in this fork.
6668

67-
New `RemoveCIDRs` functions were added (in June 2022) to remove/exclude CIDR blocks or IP ranges.
69+
New `RemoveCIDRs` functions added (in June 2022) to remove/exclude CIDR blocks or IP ranges.
70+
71+
New `SubsetCIDRs` functions added (in September 2022) to select specific CIDR blocks or IP ranges to keep.
72+
A bit like the oposite of RemoveCIDRs, `SubsetCIDRs` selects what to keep instead of what to remove.
6873

6974
## Upcoming
7075

71-
New `SubsetCIDRs` functions are planned to select specific CIDR blocks or IP ranges to keep.
76+
New `DiffCIDRs` functions are planned to compare two lists of CIDR blocks or IP ranges.

ipv4.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,70 @@ func remove4(blocks, removes cidrBlock4s) ([]*net.IPNet, error) {
240240

241241
return merged, nil
242242
}
243+
244+
// subset4 accepts two lists of IPv4 networks and return a new list of IPNets that exsists/overlaps in both lists.
245+
// The subset4() will return the smallest possible list of IPNets.
246+
func subset4(blocks, subsets cidrBlock4s) ([]*net.IPNet, error) {
247+
sort.Sort(blocks)
248+
sort.Sort(subsets)
249+
250+
i := 0
251+
j := 0
252+
for i < len(blocks) {
253+
if j >= len(subsets) || blocks[i].last < subsets[j].first {
254+
// No more subset blocks to compare with (then no more network blocks to keep), or
255+
// network-block entirely before subset-block, remove block and continue with next
256+
//
257+
// Clear network-block and continue to next
258+
blocks[i] = nil
259+
i++
260+
} else if subsets[j].last < blocks[i].first {
261+
// Subset-block entirely before network-block, use next subset-block
262+
j++
263+
} else if blocks[i].first >= subsets[j].first && blocks[i].last <= subsets[j].last {
264+
// Network-block inside subset-block, keep that network-block
265+
i++
266+
// From here on we have some sort of overlap
267+
} else if blocks[i].first >= subsets[j].first {
268+
// Network-block starts inside subset-block, adjust end of network-block
269+
blocks[i].last = subsets[j].last
270+
i++
271+
j++
272+
} else if blocks[i].last <= subsets[j].last {
273+
// Network-block ends inside subset-block, adjust start of network-block
274+
blocks[i].first = subsets[j].first
275+
i++
276+
} else {
277+
// Subset-block inside network-block, adjust both start and end of network-block
278+
blocks[i].first = subsets[j].first
279+
// Check if next subset-block exists and starts with network-block
280+
if j < len(subsets) - 1 && subsets[j+1].first < blocks[i].last {
281+
// Make room for new network block
282+
blocks = append(blocks, nil)
283+
copy(blocks[i+1:], blocks[i:])
284+
blocks[i] = new(cidrBlock4)
285+
// update first half of the network-block (new)
286+
blocks[i].first = subsets[j].first
287+
// Update second half of the network-block (old)
288+
blocks[i+1].first = subsets[j+1].first
289+
}
290+
// Finaly handle (first) network-block's last address
291+
blocks[i].last = subsets[j].last
292+
i++
293+
j++
294+
}
295+
}
296+
297+
var overlaps []*net.IPNet
298+
for _, block := range blocks {
299+
if block == nil {
300+
continue
301+
}
302+
303+
if err := splitRange4(0, 0, block.first, block.last, &overlaps); err != nil {
304+
return nil, err
305+
}
306+
}
307+
308+
return overlaps, nil
309+
}

ipv6.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,70 @@ func remove6(blocks, removes cidrBlock6s) ([]*net.IPNet, error) {
254254

255255
return merged, nil
256256
}
257+
258+
// subset6 accepts two lists of IPv6 networks and return a new list of IPNets that exsists/overlaps in both lists.
259+
// The subset6() will return the smallest possible list of IPNets.
260+
func subset6(blocks, subsets cidrBlock6s) ([]*net.IPNet, error) {
261+
sort.Sort(blocks)
262+
sort.Sort(subsets)
263+
264+
i := 0
265+
j := 0
266+
for i < len(blocks) {
267+
if j >= len(subsets) || blocks[i].last.Cmp(subsets[j].first) < 0 {
268+
// No more subset blocks to compare with (then no more network blocks to keep), or
269+
// network-block entirely before subset-block, remove block and continue with next
270+
//
271+
// Clear network-block and continue to next
272+
blocks[i] = nil
273+
i++
274+
} else if subsets[j].last.Cmp(blocks[i].first) < 0 {
275+
// Subset-block entirely before network-block, use next subset-block
276+
j++
277+
} else if blocks[i].first.Cmp(subsets[j].first) >= 0 && blocks[i].last.Cmp(subsets[j].last) <= 0 {
278+
// Network-block inside subset-block, keep that network-block
279+
i++
280+
// From here on we have some sort of overlap
281+
} else if blocks[i].first.Cmp(subsets[j].first) >= 0 {
282+
// Network-block starts inside subset-block, adjust end of network-block
283+
blocks[i].last = subsets[j].last
284+
i++
285+
j++
286+
} else if blocks[i].last.Cmp(subsets[j].last) <= 0 {
287+
// Network-block ends inside subset-block, adjust start of network-block
288+
blocks[i].first = subsets[j].first
289+
i++
290+
} else {
291+
// Subset-block inside network-block, adjust both start and end of network-block
292+
blocks[i].first = subsets[j].first
293+
// Check if next subset-block exists and starts with network-block
294+
if j < len(subsets) - 1 && subsets[j+1].first.Cmp(blocks[i].last) < 0 {
295+
// Make room for new network block
296+
blocks = append(blocks, nil)
297+
copy(blocks[i+1:], blocks[i:])
298+
blocks[i] = new(cidrBlock6)
299+
// update first half of the network-block (new)
300+
blocks[i].first = subsets[j].first
301+
// Update second half of the network-block (old)
302+
blocks[i+1].first = subsets[j+1].first
303+
}
304+
// Finaly handle (first) network-block's last address
305+
blocks[i].last = subsets[j].last
306+
i++
307+
j++
308+
}
309+
}
310+
311+
var overlaps []*net.IPNet
312+
for _, block := range blocks {
313+
if block == nil {
314+
continue
315+
}
316+
317+
if err := splitRange6(big.NewInt(0), 0, block.first, block.last, &overlaps); err != nil {
318+
return nil, err
319+
}
320+
}
321+
322+
return overlaps, nil
323+
}

merge.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ func (nets ipNets) toCIDRs() []string {
1414
for _, net := range nets {
1515
cidrs = append(cidrs, net.String())
1616
}
17-
1817
return cidrs
1918
}
2019

@@ -29,7 +28,7 @@ func MergeIPNets(nets []*net.IPNet) ([]*net.IPNet, error) {
2928
}
3029

3130
// Split into IPv4 and IPv6 lists.
32-
// Merge the list separately and then combine.
31+
// Handle the lists separately and then combine.
3332
var block4s cidrBlock4s
3433
var block6s cidrBlock6s
3534
for _, net := range nets {
@@ -42,14 +41,21 @@ func MergeIPNets(nets []*net.IPNet) ([]*net.IPNet, error) {
4241
}
4342
}
4443

45-
merged4, err := merge4(block4s)
46-
if err != nil {
47-
return nil, err
44+
var merged4 []*net.IPNet
45+
var err error
46+
if len(block4s) > 0 {
47+
merged4, err = merge4(block4s)
48+
if err != nil {
49+
return nil, err
50+
}
4851
}
4952

50-
merged6, err := merge6(block6s)
51-
if err != nil {
52-
return nil, err
53+
var merged6 []*net.IPNet
54+
if len(block6s) > 0 {
55+
merged6, err = merge6(block6s)
56+
if err != nil {
57+
return nil, err
58+
}
5359
}
5460

5561
merged := append(merged4, merged6...)

remove.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func RemoveIPNets(nets, rmnets []*net.IPNet) ([]*net.IPNet, error) {
3333
}
3434

3535
// Split into IPv4 and IPv6 lists.
36-
// Merge the list separately and then combine.
36+
// Handle the lists separately and then combine.
3737
var block4s cidrBlock4s
3838
var block6s cidrBlock6s
3939
for _, net := range nets {
@@ -57,14 +57,20 @@ func RemoveIPNets(nets, rmnets []*net.IPNet) ([]*net.IPNet, error) {
5757
}
5858
}
5959

60-
new4s, err := remove4(block4s, remove4s)
61-
if err != nil {
62-
return nil, err
60+
var new4s []*net.IPNet
61+
if len(block4s) > 0 {
62+
new4s, err = remove4(block4s, remove4s)
63+
if err != nil {
64+
return nil, err
65+
}
6366
}
6467

65-
new6s, err := remove6(block6s, remove6s)
66-
if err != nil {
67-
return nil, err
68+
var new6s []*net.IPNet
69+
if len(block6s) > 0 {
70+
new6s, err = remove6(block6s, remove6s)
71+
if err != nil {
72+
return nil, err
73+
}
6874
}
6975

7076
merged := append(new4s, new6s...)

remove_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"testing"
88
)
99

10-
func TestRremoveCIDRs(t *testing.T) {
10+
func TestRemoveCIDRs(t *testing.T) {
1111
type TestCase struct {
1212
Input []string
1313
Remove []string

0 commit comments

Comments
 (0)