-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9d8266c
commit dea21da
Showing
25 changed files
with
3,317 additions
and
905 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package acloptimizer | ||
|
||
import ( | ||
"slices" | ||
|
||
"github.com/np-guard/models/pkg/ds" | ||
"github.com/np-guard/models/pkg/netp" | ||
"github.com/np-guard/models/pkg/netset" | ||
"github.com/np-guard/vpc-network-config-synthesis/pkg/ir" | ||
"github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" | ||
) | ||
|
||
func aclCubesToRules(cubes *aclCubesPerProtocol, direction ir.Direction) []*ir.ACLRule { | ||
reduceACLCubes(cubes) | ||
tcpRules := tcpudpTriplesToRules(cubes.tcpAllow, direction) | ||
udpRules := tcpudpTriplesToRules(cubes.udpAllow, direction) | ||
icmpRules := icmpTriplesToRules(cubes.icmpAllow, direction) | ||
anyProtocolRules := anyProtocolCubesToRules(cubes.anyProtocolAllow, direction) | ||
return slices.Concat(tcpRules, udpRules, icmpRules, anyProtocolRules) | ||
} | ||
|
||
// same algorithm as sg cubes to rules | ||
func anyProtocolCubesToRules(cubes srcDstProduct, direction ir.Direction) []*ir.ACLRule { | ||
partitions := optimize.SortPartitionsByIPAddrs(cubes.Partitions()) | ||
if len(partitions) == 0 { | ||
return []*ir.ACLRule{} | ||
} | ||
|
||
res := make([]*ir.ACLRule, 0) | ||
activeRules := make([]ds.Pair[*netset.IPBlock, *netset.IPBlock], 0) // Left = first src's IP, Right = dst cidr | ||
|
||
for i := range partitions { | ||
// if it is not possible to continue the rule between the cubes, generate all existing rules | ||
if i > 0 && uncoveredHole(partitions[i-1].Left, partitions[i].Left) { | ||
res = slices.Concat(res, createActiveRules(activeRules, partitions[i-1].Left.LastIPAddressObject(), direction)) | ||
activeRules = make([]ds.Pair[*netset.IPBlock, *netset.IPBlock], 0) | ||
} | ||
|
||
// if there are active rules whose dsts are not fully included in the current cube, they will be created | ||
// also activeDstIPs will be calculated, which is the dstIPs that are still included in the active rules | ||
activeDstIPs := netset.NewIPBlock() | ||
for j, rule := range slices.Backward(activeRules) { | ||
if rule.Right.IsSubset(partitions[i].Right) { | ||
activeDstIPs = activeDstIPs.Union(rule.Right) | ||
} else { | ||
res = createNewRules(rule.Left, partitions[i-1].Left.LastIPAddressObject(), rule.Right, direction) // create active rule | ||
activeRules = slices.Delete(activeRules, j, j+1) | ||
} | ||
} | ||
|
||
// if the current cube contains dstIPs that are not contained in active rules, new rules will be created | ||
for _, dstCidr := range partitions[i].Right.SplitToCidrs() { | ||
if !dstCidr.IsSubset(activeDstIPs) { | ||
rule := ds.Pair[*netset.IPBlock, *netset.IPBlock]{Left: partitions[i].Left.FirstIPAddressObject(), Right: dstCidr} | ||
activeRules = append(activeRules, rule) | ||
} | ||
} | ||
} | ||
// generate all existing rules | ||
return slices.Concat(res, createActiveRules(activeRules, partitions[len(partitions)-1].Left.LastIPAddressObject(), direction)) | ||
} | ||
|
||
func createActiveRules(activeRules []ds.Pair[*netset.IPBlock, *netset.IPBlock], srcLastIP *netset.IPBlock, | ||
direction ir.Direction) []*ir.ACLRule { | ||
res := make([]*ir.ACLRule, 0) | ||
for _, rule := range activeRules { | ||
res = slices.Concat(res, createNewRules(rule.Left, srcLastIP, rule.Right, direction)) | ||
} | ||
return res | ||
} | ||
|
||
func createNewRules(srcStartIP, srcEndIP, dstCidr *netset.IPBlock, direction ir.Direction) []*ir.ACLRule { | ||
src, _ := netset.IPBlockFromIPRange(srcStartIP, srcEndIP) | ||
srcCidrs := src.SplitToCidrs() | ||
|
||
res := make([]*ir.ACLRule, len(srcCidrs)) | ||
for i, srcCidr := range srcCidrs { | ||
res[i] = ir.NewACLRule(ir.Allow, direction, srcCidr, dstCidr, netp.AnyProtocol{}, "") | ||
} | ||
return res | ||
} | ||
|
||
func uncoveredHole(prevSrcIP, currSrcIP *netset.IPBlock) bool { | ||
touching, _ := prevSrcIP.TouchingIPRanges(currSrcIP) | ||
return !touching | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package acloptimizer | ||
|
||
import ( | ||
"slices" | ||
|
||
"github.com/np-guard/models/pkg/ds" | ||
"github.com/np-guard/models/pkg/netp" | ||
"github.com/np-guard/models/pkg/netset" | ||
"github.com/np-guard/vpc-network-config-synthesis/pkg/ir" | ||
"github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" | ||
) | ||
|
||
func icmpTriplesToRules(tripleSet icmpTripleSet, direction ir.Direction) []*ir.ACLRule { | ||
partitions := minimalPartitionsICMP(tripleSet) | ||
res := make([]*ir.ACLRule, len(partitions)) | ||
for i, t := range partitions { | ||
res[i] = ir.NewACLRule(ir.Allow, direction, t.S1, t.S2, t.S3, "") | ||
} | ||
return res | ||
} | ||
|
||
func minimalPartitionsICMP(t icmpTripleSet) []ds.Triple[*netset.IPBlock, *netset.IPBlock, netp.ICMP] { | ||
leftPartitions := actualPartitionsICMP(ds.AsLeftTripleSet(t)) | ||
outerPartitions := actualPartitionsICMP(ds.AsOuterTripleSet(t)) | ||
rightPartitions := actualPartitionsICMP(ds.AsRightTripleSet(t)) | ||
|
||
switch { | ||
case len(leftPartitions) <= len(outerPartitions) && len(leftPartitions) <= len(rightPartitions): | ||
return leftPartitions | ||
case len(outerPartitions) <= len(leftPartitions) && len(outerPartitions) <= len(rightPartitions): | ||
return outerPartitions | ||
default: | ||
return rightPartitions | ||
} | ||
} | ||
|
||
func actualPartitionsICMP(t icmpTripleSet) []ds.Triple[*netset.IPBlock, *netset.IPBlock, netp.ICMP] { | ||
res := make([]ds.Triple[*netset.IPBlock, *netset.IPBlock, netp.ICMP], 0) | ||
for _, p := range t.Partitions() { | ||
res = slices.Concat(res, breakICMPTriple(p)) | ||
} | ||
return res | ||
} | ||
|
||
// break multi-cube to regular cube | ||
func breakICMPTriple(t ds.Triple[*netset.IPBlock, *netset.IPBlock, *netset.ICMPSet]) []ds.Triple[*netset.IPBlock, | ||
*netset.IPBlock, netp.ICMP] { | ||
res := make([]ds.Triple[*netset.IPBlock, *netset.IPBlock, netp.ICMP], 0) | ||
|
||
dstCidrs := t.S2.SplitToCidrs() | ||
icmpPartitions := optimize.IcmpsetPartitions(t.S3) | ||
|
||
for _, src := range t.S1.SplitToCidrs() { | ||
for _, dst := range dstCidrs { | ||
for _, icmp := range icmpPartitions { | ||
a := ds.Triple[*netset.IPBlock, *netset.IPBlock, netp.ICMP]{S1: src, S2: dst, S3: icmp} | ||
res = append(res, a) | ||
} | ||
} | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package acloptimizer | ||
|
||
import ( | ||
"github.com/np-guard/models/pkg/ds" | ||
"github.com/np-guard/models/pkg/netset" | ||
) | ||
|
||
// reduceACLCubes unifies a (src ip x dst ip) cube, separately allowed for tcp, udp and icmp, into one "any" cube | ||
// (assuming all ports, codes, types) | ||
func reduceACLCubes(aclCubes *aclCubesPerProtocol) { | ||
allTCP := allTCPUDP(aclCubes.tcpAllow) | ||
allUDP := allTCPUDP(aclCubes.udpAllow) | ||
allicmp := allICMP(aclCubes.icmpAllow) | ||
aclCubes.anyProtocolAllow = allTCP.Intersect(allUDP).Intersect(allicmp) | ||
subtractAnyProtocolCubes(aclCubes) | ||
} | ||
|
||
func allTCPUDP(tcpudpAllow ds.TripleSet[*netset.IPBlock, *netset.IPBlock, *netset.TCPUDPSet]) *srcDstProductLeft { | ||
res := ds.NewProductLeft[*netset.IPBlock, *netset.IPBlock]() | ||
allTCPSet := netset.NewAllTCPOnlySet() | ||
allUDPSet := netset.NewAllUDPOnlySet() | ||
for _, p := range tcpudpAllow.Partitions() { | ||
if p.S3.Equal(allTCPSet) || p.S3.Equal(allUDPSet) { // all tcp or udp ports | ||
r := ds.CartesianPairLeft(p.S1, p.S2) | ||
res = res.Union(r).(*srcDstProductLeft) | ||
} | ||
} | ||
return res | ||
} | ||
|
||
func allICMP(icmpAllow ds.TripleSet[*netset.IPBlock, *netset.IPBlock, *netset.ICMPSet]) *srcDstProductLeft { | ||
res := ds.NewProductLeft[*netset.IPBlock, *netset.IPBlock]() | ||
for _, p := range icmpAllow.Partitions() { | ||
if p.S3.IsAll() { // all icmp types and codes | ||
r := ds.CartesianPairLeft(p.S1, p.S2) | ||
res = res.Union(r).(*srcDstProductLeft) | ||
} | ||
} | ||
return res | ||
} | ||
|
||
func subtractAnyProtocolCubes(aclCubes *aclCubesPerProtocol) { | ||
allTcpudp := ds.NewLeftTripleSet[*netset.IPBlock, *netset.IPBlock, *netset.TCPUDPSet]() | ||
allIcmp := ds.NewLeftTripleSet[*netset.IPBlock, *netset.IPBlock, *netset.ICMPSet]() | ||
for _, p := range aclCubes.anyProtocolAllow.Partitions() { | ||
t := ds.CartesianLeftTriple(p.Left, p.Right, netset.AllTCPUDPSet()) | ||
allTcpudp = allTcpudp.Union(t).(*ds.LeftTripleSet[*netset.IPBlock, *netset.IPBlock, *netset.TCPUDPSet]) | ||
i := ds.CartesianLeftTriple(p.Left, p.Right, netset.AllICMPSet()) | ||
allIcmp = allIcmp.Union(i).(*ds.LeftTripleSet[*netset.IPBlock, *netset.IPBlock, *netset.ICMPSet]) | ||
} | ||
|
||
aclCubes.tcpAllow = aclCubes.tcpAllow.Subtract(allTcpudp) | ||
aclCubes.udpAllow = aclCubes.udpAllow.Subtract(allTcpudp) | ||
aclCubes.icmpAllow = aclCubes.icmpAllow.Subtract(allIcmp) | ||
} |
Oops, something went wrong.