Skip to content

Commit

Permalink
cilium: Added support to generate icmp rules
Browse files Browse the repository at this point in the history
Signed-off-by: Wazir Ahmed <wazir@accuknox.com>
  • Loading branch information
wazir-ahmed committed Mar 18, 2022
1 parent bb633eb commit 40cfbe2
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 105 deletions.
2 changes: 1 addition & 1 deletion src/config/configManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func LoadConfigFromFile() {
NetworkPolicyDir: viper.GetString("application.network.network-policy-dir"),

NetPolicyTypes: 3,
NetPolicyRuleTypes: 511,
NetPolicyRuleTypes: 1023,
NetPolicyCIDRBits: 32,

NetLogFilters: []types.NetworkLogFilter{},
Expand Down
43 changes: 37 additions & 6 deletions src/libs/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ var GitBranch string
var BuildDate string
var Version string

const (
IPProtoUnknown = -1
IPProtocolICMP = 1
IPProtocolTCP = 6
IPProtocolUDP = 17
IPProtocolICMPv6 = 58
IPProtocolSCTP = 132
)

var protocolMap = map[int]string{
IPProtoUnknown: "Unknown",
IPProtocolICMP: "ICMP",
IPProtocolTCP: "TCP",
IPProtocolUDP: "UDP",
IPProtocolICMPv6: "ICMPv6",
IPProtocolSCTP: "SCTP",
}

// Array for ICMP type which can be considered as ICMP reply packets.
// TODO: Identity all the ICMP reply types
var ICMPReplyType = []int{
0, // EchoReply
}

func printBuildDetails() {
if GitCommit == "" {
return
Expand Down Expand Up @@ -210,14 +234,21 @@ func GetExternalIPAddr() string {
}

func GetProtocol(protocol int) string {
protocolMap := map[int]string{
1: "ICMP",
6: "TCP",
17: "UDP",
132: "STCP",
return protocolMap[protocol]
}

func IsICMP(protocol int) bool {
if protocol == IPProtocolICMP || protocol == IPProtocolICMPv6 {
return true
}
return false
}

return protocolMap[protocol]
func IsReplyICMP(icmpType int) bool {
if ContainsElement(ICMPReplyType, icmpType) {
return true
}
return false
}

// ============ //
Expand Down
124 changes: 100 additions & 24 deletions src/networkpolicy/deduplicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,9 @@ func UpdateHTTP(newPolicy types.KnoxNetworkPolicy, existingPolicies []types.Knox
func UpdateToPorts(newPolicy types.KnoxNetworkPolicy, existingPolicies []types.KnoxNetworkPolicy) (types.KnoxNetworkPolicy, bool) {
// case 1: if there is no latest, policy is new one
latestPolicies := []types.KnoxNetworkPolicy{}
if newPolicy.Metadata["rule"] == "toCIDRs+toPorts" {
if strings.Contains(newPolicy.Metadata["rule"], "toCIDRs") {
latestPolicies = GetLatestCIDRPolicy(existingPolicies, newPolicy)
} else if newPolicy.Metadata["rule"] == "toFQDNs+toPorts" {
} else if strings.Contains(newPolicy.Metadata["rule"], "toFQDNs") {
latestPolicies = GetLatestFQDNPolicy(existingPolicies, newPolicy)
} else {
return newPolicy, true
Expand All @@ -357,31 +357,46 @@ func UpdateToPorts(newPolicy types.KnoxNetworkPolicy, existingPolicies []types.K
}

newToPorts := []types.SpecPort{}
newICMPs := []types.SpecICMP{}
if newPolicy.Metadata["type"] == "egress" {
newToPorts = newPolicy.Spec.Egress[0].ToPorts
newICMPs = newPolicy.Spec.Egress[0].ICMPs
} else {
newToPorts = newPolicy.Spec.Ingress[0].ToPorts
newICMPs = newPolicy.Spec.Ingress[0].ICMPs
}

updated := false

for _, latestPolicy := range latestPolicies {
existToPorts := []types.SpecPort{}
existICMPs := []types.SpecICMP{}
if newPolicy.Metadata["type"] == "egress" {
existToPorts = latestPolicy.Spec.Egress[0].ToPorts
existICMPs = latestPolicy.Spec.Egress[0].ICMPs
} else {
existToPorts = latestPolicy.Spec.Ingress[0].ToPorts
existICMPs = latestPolicy.Spec.Ingress[0].ICMPs
}

includeAllRules := true
for _, rule := range newToPorts {
if !libs.ContainsElement(existToPorts, rule) {
includeAllRules = false
includedAllPortRules := true
for _, port := range newToPorts {
if !libs.ContainsElement(existToPorts, port) {
includedAllPortRules = false
break
}
}

// case 2: policy has toPorts, which are all includes in latest one
if includeAllRules {
includedAllICMPRules := true
for _, icmp := range newICMPs {
if !libs.ContainsElement(existICMPs, icmp) {
includedAllICMPRules = false
break
}
}

// case 2: policy has toPorts & icmps, which are all included in latest one
if includedAllPortRules && includedAllICMPRules {
// case 2-1: policy has the lower selector count? outdated
if len(newPolicy.Spec.Selector.MatchLabels) < len(latestPolicy.Spec.Selector.MatchLabels) {
updateOutdatedPolicy(latestPolicy, &newPolicy)
Expand All @@ -391,10 +406,20 @@ func UpdateToPorts(newPolicy types.KnoxNetworkPolicy, existingPolicies []types.K
continue // next existPolicy
}

// case 3: policy has toPorts, latest has toPorts or no toPorts --> move to new policy
for _, toPort := range existToPorts {
if !libs.ContainsElement(newToPorts, toPort) {
newToPorts = append(newToPorts, toPort)
// case 3: policy has toPorts or icmps which are not included in latest one
if !includedAllPortRules {
for _, toPort := range existToPorts {
if !libs.ContainsElement(newToPorts, toPort) {
newToPorts = append(newToPorts, toPort)
}
}
}

if !includedAllICMPRules {
for _, icmp := range existICMPs {
if !libs.ContainsElement(newICMPs, icmp) {
newICMPs = append(newICMPs, icmp)
}
}
}

Expand All @@ -407,10 +432,11 @@ func UpdateToPorts(newPolicy types.KnoxNetworkPolicy, existingPolicies []types.K
if updated {
if newPolicy.Metadata["type"] == "egress" {
newPolicy.Spec.Egress[0].ToPorts = newToPorts
newPolicy.Spec.Egress[0].ICMPs = newICMPs
} else {
newPolicy.Spec.Ingress[0].ToPorts = newToPorts
newPolicy.Spec.Ingress[0].ICMPs = newICMPs
}

return newPolicy, true
}

Expand All @@ -424,39 +450,54 @@ func UpdateMatchLabels(newPolicy types.KnoxNetworkPolicy, existingPolicies []typ
return newPolicy, true
}

newICMPs := []types.SpecICMP{}
newToPorts := []types.SpecPort{}
newTargetLabelsCount := 0
if newPolicy.Metadata["type"] == "egress" {
newToPorts = newPolicy.Spec.Egress[0].ToPorts
newICMPs = newPolicy.Spec.Egress[0].ICMPs
newTargetLabelsCount = len(newPolicy.Spec.Egress[0].MatchLabels)
} else {
newToPorts = newPolicy.Spec.Ingress[0].ToPorts
newICMPs = newPolicy.Spec.Egress[0].ICMPs
newTargetLabelsCount = len(newPolicy.Spec.Ingress[0].MatchLabels)
}

updated := false

for _, latestPolicy := range latestPolicies {
existToPorts := []types.SpecPort{}
existICMPs := []types.SpecICMP{}
existTargetLabelsCount := 0

if newPolicy.Metadata["type"] == "egress" {
existToPorts = latestPolicy.Spec.Egress[0].ToPorts
existICMPs = latestPolicy.Spec.Egress[0].ICMPs
existTargetLabelsCount = len(latestPolicy.Spec.Egress[0].MatchLabels)
} else {
existToPorts = latestPolicy.Spec.Ingress[0].ToPorts
existICMPs = latestPolicy.Spec.Ingress[0].ICMPs
existTargetLabelsCount = len(latestPolicy.Spec.Ingress[0].MatchLabels)
}

includeAllRules := true
includedAllPortRules := true
for _, rule := range newToPorts {
if !libs.ContainsElement(existToPorts, rule) {
includeAllRules = false
includedAllPortRules = false
break
}
}

// case 2: policy has toPorts, which are all includes in latest one
if includeAllRules {
includedAllICMPRules := true
for _, icmp := range newICMPs {
if !libs.ContainsElement(existICMPs, icmp) {
includedAllICMPRules = false
break
}
}

// case 2: policy has toPorts & icmps, which are all included in latest one
if includedAllPortRules && includedAllICMPRules {
// case 2-1: policy has the lower selector count? outdated
if len(newPolicy.Spec.Selector.MatchLabels) < len(latestPolicy.Spec.Selector.MatchLabels) ||
newTargetLabelsCount < existTargetLabelsCount {
Expand All @@ -468,10 +509,20 @@ func UpdateMatchLabels(newPolicy types.KnoxNetworkPolicy, existingPolicies []typ
continue // next existPolicy
}

// case 3: policy has toPorts, latest has toPorts or no toPorts --> move to new policy
for _, toPort := range existToPorts {
if !libs.ContainsElement(newToPorts, toPort) {
newToPorts = append(newToPorts, toPort)
// case 3: policy has toPorts or icmps which are not included in latest one
if !includedAllPortRules {
for _, toPort := range existToPorts {
if !libs.ContainsElement(newToPorts, toPort) {
newToPorts = append(newToPorts, toPort)
}
}
}

if !includedAllICMPRules {
for _, icmp := range existICMPs {
if !libs.ContainsElement(newICMPs, icmp) {
newICMPs = append(newICMPs, icmp)
}
}
}

Expand All @@ -484,8 +535,9 @@ func UpdateMatchLabels(newPolicy types.KnoxNetworkPolicy, existingPolicies []typ
if updated {
if newPolicy.Metadata["type"] == "egress" {
newPolicy.Spec.Egress[0].ToPorts = newToPorts
newPolicy.Spec.Egress[0].ICMPs = newICMPs
} else {
newPolicy.Spec.Ingress[0].ToPorts = newToPorts
newPolicy.Spec.Ingress[0].ICMPs = newICMPs
}

return newPolicy, true
Expand Down Expand Up @@ -747,6 +799,30 @@ func updateExistCIDRtoNewFQDN(existingPolicies []types.KnoxNetworkPolicy, newPol
}
}

if len(existCIDR.Spec.Egress[0].ICMPs) > 0 {
// if cidr has ICMPs also, check duplication as well
cidrICMPs := existCIDR.Spec.Egress[0].ICMPs
fqdnICMPs := fqdnPolicy.Spec.Egress[0].ICMPs
if fqdnICMPs == nil {
fqdnICMPs = []types.SpecICMP{}
}

// move cidr's ICMPs -> fqdn's ICMPs
for _, icmp := range cidrICMPs {
if !libs.ContainsElement(fqdnICMPs, icmp) {
fqdnICMPs = append(fqdnICMPs, icmp)
}
}

// updated fqdn -> newPolicies
fqdnPolicy.Spec.Egress[0].ICMPs = fqdnICMPs
for i, exist := range newPolicies {
if fqdnPolicy.Metadata["name"] == exist.Metadata["name"] {
newPolicies[i] = fqdnPolicy
}
}
}

libs.UpdateOutdatedNetworkPolicy(CfgDB, existCIDR.Metadata["name"], fqdnPolicy.Metadata["name"])
}
}
Expand Down Expand Up @@ -815,7 +891,7 @@ func UpdateDuplicatedPolicy(existingPolicies []types.KnoxNetworkPolicy, discover
}

// step 5: update existing FQDN+toPorts rules: egress
if strings.Contains(policy.Metadata["rule"], "toFQDNs") && policy.Metadata["rule"] == "egress" {
if strings.Contains(policy.Metadata["rule"], "toFQDNs") && policy.Metadata["type"] == "egress" {
updatedPolicy, updated := UpdateToPorts(namedPolicy, existingPolicies)
if updated {
namedPolicy = updatedPolicy
Expand All @@ -831,7 +907,7 @@ func UpdateDuplicatedPolicy(existingPolicies []types.KnoxNetworkPolicy, discover
}

// step 7: update existing Entities rules: egress
if strings.Contains(policy.Metadata["rule"], "toServices") && policy.Metadata["rule"] == "egress" {
if strings.Contains(policy.Metadata["rule"], "toServices") && policy.Metadata["type"] == "egress" {
updatedPolicy, updated := UpdateService(namedPolicy, existingPolicies)
if updated {
namedPolicy = updatedPolicy
Expand Down
14 changes: 9 additions & 5 deletions src/networkpolicy/helperFunctions.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,22 @@ func FilterNetworkLogsByConfig(logs []types.KnoxNetworkLog, pods []types.Pod) []
for _, log := range logs {
filtered := false

if log.Protocol == 6 && !log.SynFlag { // In case of TCP only handle flows with SYN flag
if log.Protocol == libs.IPProtocolTCP && !log.SynFlag { // In case of TCP only handle flows with SYN flag
continue
}

if log.Protocol == 17 && log.IsReply && log.DstNamespace == "reserved:world" {
if log.Protocol == libs.IPProtocolUDP && log.IsReply && log.DstNamespace == "reserved:world" {
/*
fmt.Printf("dropping UDP SrcPort:%v DstPort:%v DstNamespace:%v\n",
log.SrcPort, log.DstPort, log.DstNamespace)
*/
continue
}

if libs.IsICMP(log.Protocol) && log.IsReply {
continue
}

for _, filter := range NetworkLogFilters {
checkItems := getHaveToCheckItems(filter)

Expand Down Expand Up @@ -639,15 +643,15 @@ func checkK8sExternalService(log types.KnoxNetworkLog, endpoints []types.Endpoin
}

func isExposedPort(protocol int, port int) bool {
if protocol == 6 { // tcp
if protocol == libs.IPProtocolTCP {
if libs.ContainsElement(K8sServiceTCPPorts, port) {
return true
}
} else if protocol == 17 { // udp
} else if protocol == libs.IPProtocolUDP {
if libs.ContainsElement(K8sServiceUDPPorts, port) {
return true
}
} else if protocol == 132 { // sctp
} else if protocol == libs.IPProtocolSCTP {
if libs.ContainsElement(K8sServiceSCTPPorts, port) {
return true
}
Expand Down
Loading

0 comments on commit 40cfbe2

Please sign in to comment.