diff --git a/pkg/connection/connection.go b/pkg/connection/connection.go deleted file mode 100644 index 1e4c4d0..0000000 --- a/pkg/connection/connection.go +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright 2023- IBM Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package connection - -import ( - "github.com/np-guard/models/pkg/netp" - "github.com/np-guard/models/pkg/netset" -) - -// Set captures a set of connections for protocols TCP/UPD/ICMP with their properties (ports/icmp type&code) -type Set = netset.TransportSet - -// NewTCPorUDP returns a set of connections containing the specified protocol (TCP/UDP) and ports -func NewTCPorUDP(protocol netp.ProtocolString, srcMinP, srcMaxP, dstMinP, dstMaxP int64) *Set { - return netset.NewTCPorUDPTransport(protocol, srcMinP, srcMaxP, dstMinP, dstMaxP) -} - -// NewTCP returns a set of TCP connections containing the specified ports -func NewTCP(srcMinP, srcMaxP, dstMinP, dstMaxP int64) *Set { - return NewTCPorUDP(netp.ProtocolStringTCP, srcMinP, srcMaxP, dstMinP, dstMaxP) -} - -// NewUDP returns a set of UDP connections containing the specified ports -func NewUDP(srcMinP, srcMaxP, dstMinP, dstMaxP int64) *Set { - return NewTCPorUDP(netp.ProtocolStringUDP, srcMinP, srcMaxP, dstMinP, dstMaxP) -} - -// AllTCPorUDP returns a set of connections containing the specified protocol (TCP/UDP) with all possible ports -func AllTCPorUDP(protocol netp.ProtocolString) *Set { - return NewTCPorUDP(protocol, netp.MinPort, netp.MaxPort, netp.MinPort, netp.MaxPort) -} - -// AllICMP returns a set of connections containing the ICMP protocol with all its possible types,codes -func AllICMP() *Set { - return netset.AllOrNothingTransport(false, true) -} - -// NewTCPSet returns a set of connections containing the TCP protocol with all its possible ports -func NewTCPSet() *Set { - return AllTCPorUDP(netp.ProtocolStringTCP) -} - -// NewUDPSet returns a set of connections containing the UDP protocol with all its possible ports -func NewUDPSet() *Set { - return AllTCPorUDP(netp.ProtocolStringUDP) -} - -// ICMPConnection returns a set of connections containing the ICMP protocol with specified type,code values -func ICMPConnection(icmpType, icmpCode int64) *Set { - return netset.NewICMPTransport(icmpType, icmpType, icmpCode, icmpCode) -} - -// ICMPConnectionTypeCodeRanges returns a set of connections containing the ICMP -// protocol with specified type,code ranges values -func ICMPConnectionTypeCodeRanges(minIcmpType, maxICMPType, minCode, maxCode int64) *Set { - return netset.NewICMPTransport(minIcmpType, maxICMPType, minCode, maxCode) -} - -// All returns a set of all protocols (TCP,UPD,ICMP) in the set (with all possible properties values) -func All() *Set { - return netset.AllTransportSet() -} - -// None returns an empty set of protocols connections -func None() *Set { - return netset.AllOrNothingTransport(false, false) -} diff --git a/pkg/netset/connectionset.go b/pkg/netset/connectionset.go deleted file mode 100644 index 2bbe321..0000000 --- a/pkg/netset/connectionset.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -Copyright 2023- IBM Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package netset - -import ( - "fmt" - "sort" - "strings" - - "github.com/np-guard/models/pkg/ds" -) - -// ConnectionSet captures a set of connections for tuples of (src IP range, dst IP range, connection.Set), -// where connection.Set is a set of TCP/UPD/ICMP with their properties (ports/icmp type&code) -type ConnectionSet struct { - props ds.TripleSet[*IPBlock, *IPBlock, *TransportSet] -} - -// NewConnectionSet returns an empty ConnectionSet -func NewConnectionSet() *ConnectionSet { - return &ConnectionSet{props: ds.NewLeftTripleSet[*IPBlock, *IPBlock, *TransportSet]()} -} - -// Equal returns true is this ConnectionSet captures the exact same set of connections as `other` does. -func (c *ConnectionSet) Equal(other *ConnectionSet) bool { - return c.props.Equal(other.props) -} - -// Copy returns new ConnectionSet object with same set of connections as current one -func (c *ConnectionSet) Copy() *ConnectionSet { - return &ConnectionSet{ - props: c.props.Copy(), - } -} - -// Intersect returns a ConnectionSet object with connection tuples that result from intersection of -// this and `other` sets -func (c *ConnectionSet) Intersect(other *ConnectionSet) *ConnectionSet { - return &ConnectionSet{props: c.props.Intersect(other.props)} -} - -// IsEmpty returns true of the ConnectionSet is empty -func (c *ConnectionSet) IsEmpty() bool { - return c.props.IsEmpty() -} - -// Union returns a ConnectionSet object with connection tuples that result from union of -// this and `other` sets -func (c *ConnectionSet) Union(other *ConnectionSet) *ConnectionSet { - if other.IsEmpty() { - return c.Copy() - } - if c.IsEmpty() { - return other.Copy() - } - return &ConnectionSet{ - props: c.props.Union(other.props), - } -} - -// Subtract returns a ConnectionSet object with connection tuples that result from subtraction of -// `other` from this set -func (c *ConnectionSet) Subtract(other *ConnectionSet) *ConnectionSet { - if other.IsEmpty() { - return c.Copy() - } - return &ConnectionSet{props: c.props.Subtract(other.props)} -} - -// IsSubset returns true if c is subset of other -func (c *ConnectionSet) IsSubset(other *ConnectionSet) bool { - return c.props.IsSubset(other.props) -} - -// ConnectionSetFrom returns a new ConnectionSet object from input src, dst IP-ranges sets ands -// TransportSet connections -func ConnectionSetFrom(src, dst *IPBlock, conn *TransportSet) *ConnectionSet { - return &ConnectionSet{props: ds.CartesianLeftTriple(src, dst, conn)} -} - -func (c *ConnectionSet) Partitions() []ds.Triple[*IPBlock, *IPBlock, *TransportSet] { - return c.props.Partitions() -} - -func cubeStr(c ds.Triple[*IPBlock, *IPBlock, *TransportSet]) string { - return fmt.Sprintf("src: %s, dst: %s, conns: %s", c.S1.String(), c.S2.String(), c.S3.String()) -} - -func (c *ConnectionSet) String() string { - cubes := c.Partitions() - var resStrings = make([]string, len(cubes)) - for i, cube := range cubes { - resStrings[i] = cubeStr(cube) - } - sort.Strings(resStrings) - return strings.Join(resStrings, comma) -} diff --git a/pkg/netset/netset.go b/pkg/netset/netset.go index c923a46..38deeff 100644 --- a/pkg/netset/netset.go +++ b/pkg/netset/netset.go @@ -4,11 +4,11 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -// package netset implements types for network connection sets objects and operations. +// Package netset implements types for network connection sets objects and operations. // Types defined in this package: // IPBlock - captures a set of IP ranges // TCPUDPSet - captures sets of protocols (within TCP,UDP only) and ports (source and destination) -// ICMPSet - captures sets of types,codes for ICMP protocol -// TransportSet - captures connection-sets for protocols from {TCP, UDP, ICMP} -// ConnectionSet - captures a set of connections for tuples of (src IP range, dst IP range, TransportSet) +// ICMPSet - captures sets of type,code values for ICMP protocol +// TransportSet - captures union of elements from TCPUDPSet, ICMPSet +// EndpointsTrafficSet - captures a set of traffic attribute for tuples of (source IP range, desination IP range, TransportSet) package netset diff --git a/pkg/netset/trafficset.go b/pkg/netset/trafficset.go new file mode 100644 index 0000000..1892b33 --- /dev/null +++ b/pkg/netset/trafficset.go @@ -0,0 +1,101 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package netset + +import ( + "fmt" + "sort" + "strings" + + "github.com/np-guard/models/pkg/ds" +) + +// EndpointsTrafficSet captures a set of traffic attributes for tuples of (source IP range, desination IP range, TransportSet), +// where TransportSet is a set of TCP/UPD/ICMP with their properties (src,dst ports / icmp type,code) +type EndpointsTrafficSet struct { + props ds.TripleSet[*IPBlock, *IPBlock, *TransportSet] +} + +// NewEndpointsTrafficSet returns an empty EndpointsTrafficSet +func NewEndpointsTrafficSet() *EndpointsTrafficSet { + return &EndpointsTrafficSet{props: ds.NewLeftTripleSet[*IPBlock, *IPBlock, *TransportSet]()} +} + +// Equal returns true is this EndpointsTrafficSet captures the exact same set of connections as `other` does. +func (c *EndpointsTrafficSet) Equal(other *EndpointsTrafficSet) bool { + return c.props.Equal(other.props) +} + +// Copy returns new EndpointsTrafficSet object with same set of connections as current one +func (c *EndpointsTrafficSet) Copy() *EndpointsTrafficSet { + return &EndpointsTrafficSet{ + props: c.props.Copy(), + } +} + +// Intersect returns a EndpointsTrafficSet object with connection tuples that result from intersection of +// this and `other` sets +func (c *EndpointsTrafficSet) Intersect(other *EndpointsTrafficSet) *EndpointsTrafficSet { + return &EndpointsTrafficSet{props: c.props.Intersect(other.props)} +} + +// IsEmpty returns true of the EndpointsTrafficSet is empty +func (c *EndpointsTrafficSet) IsEmpty() bool { + return c.props.IsEmpty() +} + +// Union returns a EndpointsTrafficSet object with connection tuples that result from union of +// this and `other` sets +func (c *EndpointsTrafficSet) Union(other *EndpointsTrafficSet) *EndpointsTrafficSet { + if other.IsEmpty() { + return c.Copy() + } + if c.IsEmpty() { + return other.Copy() + } + return &EndpointsTrafficSet{ + props: c.props.Union(other.props), + } +} + +// Subtract returns a EndpointsTrafficSet object with connection tuples that result from subtraction of +// `other` from this set +func (c *EndpointsTrafficSet) Subtract(other *EndpointsTrafficSet) *EndpointsTrafficSet { + if other.IsEmpty() { + return c.Copy() + } + return &EndpointsTrafficSet{props: c.props.Subtract(other.props)} +} + +// IsSubset returns true if c is subset of other +func (c *EndpointsTrafficSet) IsSubset(other *EndpointsTrafficSet) bool { + return c.props.IsSubset(other.props) +} + +// EndpointsTrafficSetFrom returns a new EndpointsTrafficSet object from input src, dst IP-ranges sets ands +// TransportSet connections +func EndpointsTrafficSetFrom(src, dst *IPBlock, conn *TransportSet) *EndpointsTrafficSet { + return &EndpointsTrafficSet{props: ds.CartesianLeftTriple(src, dst, conn)} +} + +func (c *EndpointsTrafficSet) Partitions() []ds.Triple[*IPBlock, *IPBlock, *TransportSet] { + return c.props.Partitions() +} + +func cubeStr(c ds.Triple[*IPBlock, *IPBlock, *TransportSet]) string { + return fmt.Sprintf("src: %s, dst: %s, conns: %s", c.S1.String(), c.S2.String(), c.S3.String()) +} + +func (c *EndpointsTrafficSet) String() string { + cubes := c.Partitions() + var resStrings = make([]string, len(cubes)) + for i, cube := range cubes { + resStrings[i] = cubeStr(cube) + } + sort.Strings(resStrings) + return strings.Join(resStrings, comma) +} diff --git a/pkg/netset/connectionset_test.go b/pkg/netset/trafficset_test.go similarity index 76% rename from pkg/netset/connectionset_test.go rename to pkg/netset/trafficset_test.go index edece15..7a2ff13 100644 --- a/pkg/netset/connectionset_test.go +++ b/pkg/netset/trafficset_test.go @@ -13,7 +13,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/np-guard/models/pkg/connection" "github.com/np-guard/models/pkg/netp" "github.com/np-guard/models/pkg/netset" ) @@ -30,9 +29,9 @@ func TestConnectionSetBasicOperations(t *testing.T) { rightHalfCidr1, _ := netset.IPBlockFromCidr("10.240.10.128/25") // relevant connection set objects - conn1 := netset.ConnectionSetFrom(cidr1, cidr2, connection.NewTCPSet()) // conns from cidr1 to cidr2 over all TCP - conn2 := netset.ConnectionSetFrom(cidr1, cidr1MinusCidr2, connection.NewTCPSet()) // conns from cidr1 to cidr1MinusCidr2 over all TCP - conn3 := netset.ConnectionSetFrom(cidr1, cidr1, connection.NewTCPSet()) // conns from cidr1 to cidr1 over all TCP + conn1 := netset.EndpointsTrafficSetFrom(cidr1, cidr2, netset.AllTCPSetTransport()) // conns from cidr1 to cidr2 over all TCP + conn2 := netset.EndpointsTrafficSetFrom(cidr1, cidr1MinusCidr2, netset.AllTCPSetTransport()) // conns from cidr1 to cidr1MinusCidr2 over all TCP + conn3 := netset.EndpointsTrafficSetFrom(cidr1, cidr1, netset.AllTCPSetTransport()) // conns from cidr1 to cidr1 over all TCP // basic union & Equal test unionConn := conn1.Union(conn2) @@ -40,7 +39,7 @@ func TestConnectionSetBasicOperations(t *testing.T) { require.True(t, conn3.Equal(unionConn)) // basic subtract & Equal test - conn4 := netset.ConnectionSetFrom(cidr1, cidr1MinusCidr2, connection.All()) + conn4 := netset.EndpointsTrafficSetFrom(cidr1, cidr1MinusCidr2, netset.AllTransportSet()) subtractionRes := conn3.Subtract(conn4) // removes all connections over (src1, dst2) from conn3 require.True(t, subtractionRes.Equal(conn1)) require.True(t, conn1.Equal(subtractionRes)) @@ -53,38 +52,38 @@ func TestConnectionSetBasicOperations(t *testing.T) { // basic IsEmpty test require.False(t, conn1.IsEmpty()) - require.True(t, netset.NewConnectionSet().IsEmpty()) + require.True(t, netset.NewEndpointsTrafficSet().IsEmpty()) // demonstrate split in allowed connections for dest dimension, to be reflected in partitions - conn5 := netset.ConnectionSetFrom(cidr1, subsetOfCidr1MinusCidr2, connection.AllICMP()) + conn5 := netset.EndpointsTrafficSetFrom(cidr1, subsetOfCidr1MinusCidr2, netset.AllICMPTransport()) conn5UnionConn2 := conn5.Union(conn2) // for certain dest- icmp+tcp, and for remaining dest- only tcp [common src for both] require.Equal(t, 2, len(conn5UnionConn2.Partitions())) // other operations on other objects, to get equiv object of conn5UnionConn2: - tcpAndICMP := connection.NewTCPSet().Union(connection.AllICMP()) - conn6 := netset.ConnectionSetFrom(cidr1, cidr1MinusCidr2, tcpAndICMP) + tcpAndICMP := netset.AllTCPSetTransport().Union(netset.AllICMPTransport()) + conn6 := netset.EndpointsTrafficSetFrom(cidr1, cidr1MinusCidr2, tcpAndICMP) deltaCidrs := cidr1MinusCidr2.Subtract(subsetOfCidr1MinusCidr2) - conn7 := netset.ConnectionSetFrom(cidr1, deltaCidrs, connection.AllICMP()) + conn7 := netset.EndpointsTrafficSetFrom(cidr1, deltaCidrs, netset.AllICMPTransport()) conn8 := conn6.Subtract(conn7) require.True(t, conn8.Equal(conn5UnionConn2)) // add udp to tcpAndICMP => check it is All() - conn9 := netset.ConnectionSetFrom(cidr1, cidr1MinusCidr2, connection.NewUDPSet()) - conn10 := netset.ConnectionSetFrom(cidr1, cidr1MinusCidr2, connection.All()) + conn9 := netset.EndpointsTrafficSetFrom(cidr1, cidr1MinusCidr2, netset.AllUDPSetTransport()) + conn10 := netset.EndpointsTrafficSetFrom(cidr1, cidr1MinusCidr2, netset.AllTransportSet()) conn9UnionConn6 := conn9.Union(conn6) require.True(t, conn10.Equal(conn9UnionConn6)) // demonstrate split in allowed connections for src dimensions, to be reflected in partitions // starting from conn8 - udp53 := connection.NewUDP(netp.MinPort, netp.MaxPort, 53, 53) - conn11 := netset.ConnectionSetFrom(leftHalfCidr1, subsetOfCidr1MinusCidr2, udp53) + udp53 := netset.NewUDPTransport(netp.MinPort, netp.MaxPort, 53, 53) + conn11 := netset.EndpointsTrafficSetFrom(leftHalfCidr1, subsetOfCidr1MinusCidr2, udp53) conn12 := conn11.Union(conn8) // another way to produce obj equiv to conn12 : - conn13 := netset.ConnectionSetFrom(leftHalfCidr1, subsetOfCidr1MinusCidr2, tcpAndICMP.Union(udp53)) - conn14 := netset.ConnectionSetFrom(leftHalfCidr1, cidr1MinusCidr2, connection.NewTCPSet()) - conn15 := netset.ConnectionSetFrom(rightHalfCidr1, subsetOfCidr1MinusCidr2, tcpAndICMP) - conn16 := netset.ConnectionSetFrom(rightHalfCidr1, cidr1MinusCidr2, connection.NewTCPSet()) + conn13 := netset.EndpointsTrafficSetFrom(leftHalfCidr1, subsetOfCidr1MinusCidr2, tcpAndICMP.Union(udp53)) + conn14 := netset.EndpointsTrafficSetFrom(leftHalfCidr1, cidr1MinusCidr2, netset.AllTCPSetTransport()) + conn15 := netset.EndpointsTrafficSetFrom(rightHalfCidr1, subsetOfCidr1MinusCidr2, tcpAndICMP) + conn16 := netset.EndpointsTrafficSetFrom(rightHalfCidr1, cidr1MinusCidr2, netset.AllTCPSetTransport()) conn17 := (conn13.Union(conn14)).Union(conn15.Union(conn16)) require.True(t, conn12.Equal(conn17)) diff --git a/pkg/netset/transportset.go b/pkg/netset/transportset.go index 140a824..4593001 100644 --- a/pkg/netset/transportset.go +++ b/pkg/netset/transportset.go @@ -28,6 +28,15 @@ func NewTCPorUDPTransport(protocol netp.ProtocolString, srcMinP, srcMaxP, dstMin )} } +// NewTCP returns a set of TCP connections containing the specified ports +func NewTCPTransport(srcMinP, srcMaxP, dstMinP, dstMaxP int64) *TransportSet { + return NewTCPorUDPTransport(netp.ProtocolStringTCP, srcMinP, srcMaxP, dstMinP, dstMaxP) +} + +func NewUDPTransport(srcMinP, srcMaxP, dstMinP, dstMaxP int64) *TransportSet { + return NewTCPorUDPTransport(netp.ProtocolStringUDP, srcMinP, srcMaxP, dstMinP, dstMaxP) +} + func NewICMPTransport(minType, maxType, minCode, maxCode int64) *TransportSet { return &TransportSet{ds.NewDisjoint( EmptyTCPorUDPSet(), @@ -35,6 +44,24 @@ func NewICMPTransport(minType, maxType, minCode, maxCode int64) *TransportSet { )} } +func AllTCPorUDPTransport(protocol netp.ProtocolString) *TransportSet { + return NewTCPorUDPTransport(protocol, netp.MinPort, netp.MaxPort, netp.MinPort, netp.MaxPort) +} + +func AllICMPTransport() *TransportSet { + return AllOrNothingTransport(false, true) +} + +// NewTCPSet returns a set of connections containing the TCP protocol with all its possible ports +func AllTCPSetTransport() *TransportSet { + return AllTCPorUDPTransport(netp.ProtocolStringTCP) +} + +// NewUDPSet returns a set of connections containing the UDP protocol with all its possible ports +func AllUDPSetTransport() *TransportSet { + return AllTCPorUDPTransport(netp.ProtocolStringUDP) +} + func AllOrNothingTransport(allTcpudp, allIcmp bool) *TransportSet { var tcpudp *TCPUDPSet var icmp *ICMPSet @@ -55,6 +82,10 @@ func AllTransportSet() *TransportSet { return AllOrNothingTransport(true, true) } +func EmptyTransportSet() *TransportSet { + return AllOrNothingTransport(false, false) +} + func (t *TransportSet) SwapPorts() *TransportSet { return &TransportSet{ds.NewDisjoint(t.TCPUDPSet().SwapPorts(), t.ICMPSet())} } diff --git a/pkg/connection/json.go b/pkg/netset/transportset_json.go similarity index 88% rename from pkg/connection/json.go rename to pkg/netset/transportset_json.go index ff253ff..0019d35 100644 --- a/pkg/connection/json.go +++ b/pkg/netset/transportset_json.go @@ -4,24 +4,23 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package connection +package netset import ( "github.com/np-guard/models/pkg/interval" "github.com/np-guard/models/pkg/netp" - "github.com/np-guard/models/pkg/netset" "github.com/np-guard/models/pkg/spec" ) -func getCubeAsTCPItems(srcPorts, dstPorts *netset.PortSet, p int64) []spec.TcpUdp { +func getCubeAsTCPItems(srcPorts, dstPorts *PortSet, p int64) []spec.TcpUdp { protocol := spec.TcpUdpProtocol(netp.ProtocolStringTCP) - if p == netset.UDPCode { + if p == UDPCode { protocol = spec.TcpUdpProtocol(netp.ProtocolStringUDP) } var tcpItemsTemp []spec.TcpUdp var tcpItemsFinal []spec.TcpUdp // consider src ports - if !srcPorts.Equal(netset.AllPorts()) { + if !srcPorts.Equal(AllPorts()) { // iterate the interval in the interval-set for _, span := range srcPorts.Intervals() { tcpRes := spec.TcpUdp{Protocol: protocol, MinSourcePort: int(span.Start()), MaxSourcePort: int(span.End())} @@ -31,7 +30,7 @@ func getCubeAsTCPItems(srcPorts, dstPorts *netset.PortSet, p int64) []spec.TcpUd tcpItemsTemp = append(tcpItemsTemp, spec.TcpUdp{Protocol: protocol}) } // consider dst ports - if !dstPorts.Equal(netset.AllPorts()) { + if !dstPorts.Equal(AllPorts()) { // iterate the interval in the interval-set for _, span := range dstPorts.Intervals() { for _, tcpItemTemp := range tcpItemsTemp { @@ -54,8 +53,8 @@ func getCubeAsTCPItems(srcPorts, dstPorts *netset.PortSet, p int64) []spec.TcpUd type Details spec.ProtocolList func getCubeAsICMPItems(typesSet, codesSet *interval.CanonicalSet) []spec.Icmp { - allTypes := typesSet.Equal(netset.AllICMPTypes()) - allCodes := codesSet.Equal(netset.AllICMPCodes()) + allTypes := typesSet.Equal(AllICMPTypes()) + allCodes := codesSet.Equal(AllICMPCodes()) switch { case allTypes && allCodes: return []spec.Icmp{{Protocol: spec.IcmpProtocolICMP}} @@ -88,7 +87,7 @@ func getCubeAsICMPItems(typesSet, codesSet *interval.CanonicalSet) []spec.Icmp { } // ToJSON returns a `Details` object for JSON representation of the input connection Set. -func ToJSON(c *Set) Details { +func ToJSON(c *TransportSet) Details { if c == nil { return Details{} }