Skip to content

Commit

Permalink
updated rule-matching
Browse files Browse the repository at this point in the history
  • Loading branch information
superstes committed Sep 28, 2023
1 parent b74d426 commit 42d6d5a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 63 deletions.
89 changes: 40 additions & 49 deletions lib/proc/filter/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (

func matchProtoL3(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Match {
// protocols layer 3
if rule.Match.ProtoL3N != nil && len(rule.Match.ProtoL3N) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!Proto L3: %v vs %v", rule.Match.ProtoL3N, pkt.L3.Proto))
return ruleMatch(!anyProtoMatch(rule.Match.ProtoL3N, pkt.L3.Proto))
}
if rule.Match.ProtoL3 != nil && len(rule.Match.ProtoL3) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("Proto L3: %v vs %v", rule.Match.ProtoL3, pkt.L3.Proto))
return ruleMatch(anyProtoMatch(rule.Match.ProtoL3, pkt.L3.Proto))
return anyProtoMatch(rule.Match.ProtoL3, pkt.L3.Proto)
}
if rule.Match.ProtoL3N != nil && len(rule.Match.ProtoL3N) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!Proto L3: %v vs %v", rule.Match.ProtoL3N, pkt.L3.Proto))
return negMatch(anyProtoMatch(rule.Match.ProtoL3N, pkt.L3.Proto))
}
return meta.MatchNeutral
}
Expand All @@ -27,11 +27,11 @@ func matchProtoL4(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Match {
// protocols layer 4
if rule.Match.ProtoL4 != nil && len(rule.Match.ProtoL4) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("Proto L4: %v vs %v", rule.Match.ProtoL4, pkt.L4.Proto))
return ruleMatch(anyProtoMatch(rule.Match.ProtoL4, pkt.L4.Proto))
return anyProtoMatch(rule.Match.ProtoL4, pkt.L4.Proto)
}
if rule.Match.ProtoL4N != nil && len(rule.Match.ProtoL4N) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!Proto L4: %v vs %v", rule.Match.ProtoL4N, pkt.L4.Proto))
return ruleMatch(!anyProtoMatch(rule.Match.ProtoL4N, pkt.L4.Proto))
return negMatch(anyProtoMatch(rule.Match.ProtoL4N, pkt.L4.Proto))
}
return meta.MatchNeutral
}
Expand All @@ -41,18 +41,16 @@ func matchProtoL5(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Match {
// protocols layer 5
if rule.Match.ProtoL5 != nil && pkt.L5.Proto != meta.ProtoNone {
ruleDebug(pkt, rid, fmt.Sprintf("Proto L5: %v vs %v", rule.Match.ProtoL5, pkt.L5.Proto))
if !anyProtoMatch(rule.Match.ProtoL5, pkt.L5.Proto) {
return meta.MatchNegative
} else {
result = meta.MatchPositive
result = anyProtoMatch(rule.Match.ProtoL5, pkt.L5.Proto)
if result == meta.MatchNegative {
return result
}
}
if rule.Match.ProtoL5N != nil && pkt.L5.Proto != meta.ProtoNone {
ruleDebug(pkt, rid, fmt.Sprintf("!Proto L5: %v vs %v", rule.Match.ProtoL5N, pkt.L5.Proto))
if anyProtoMatch(rule.Match.ProtoL5N, pkt.L5.Proto) {
return meta.MatchNegative
} else {
result = meta.MatchPositive
result = anyProtoMatch(rule.Match.ProtoL5N, pkt.L5.Proto)
if result == meta.MatchNegative {
return result
}
}
// todo: make sure 'none' is OK for 'pkt.L5.Encrypted'
Expand All @@ -73,15 +71,11 @@ func matchSourceNetwork(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Mat
// source network
if rule.Match.SrcNet != nil && len(rule.Match.SrcNet) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("SNet: %v vs %v", rule.Match.SrcNet, pkt.L3.SrcIP))
if !anyNetMatch(rule.Match.SrcNet, pkt.L3.SrcIP) {
result = meta.MatchNegative
} else {
result = meta.MatchPositive
}
result = anyNetMatch(rule.Match.SrcNet, pkt.L3.SrcIP)
}
if rule.Match.SrcNetN != nil && len(rule.Match.SrcNetN) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!SNet: %v vs %v", rule.Match.SrcNetN, pkt.L3.SrcIP))
return ruleMatch(!anyNetMatch(rule.Match.SrcNetN, pkt.L3.SrcIP))
return negMatch(anyNetMatch(rule.Match.SrcNetN, pkt.L3.SrcIP))
}
return result
}
Expand All @@ -91,15 +85,11 @@ func matchDestinationNetwork(pkt parse.ParsedPacket, rule cnf.Rule, rid int) met
// destination network
if rule.Match.DestNet != nil && len(rule.Match.DestNet) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("DNet: %v vs %v", rule.Match.DestNet, pkt.L3.DestIP))
if !anyNetMatch(rule.Match.DestNet, pkt.L3.DestIP) {
result = meta.MatchNegative
} else {
result = meta.MatchPositive
}
result = anyNetMatch(rule.Match.DestNet, pkt.L3.DestIP)
}
if rule.Match.DestNetN != nil && len(rule.Match.DestNetN) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!DNet: %v vs %v", rule.Match.DestNetN, pkt.L3.DestIP))
return ruleMatch(!anyNetMatch(rule.Match.DestNetN, pkt.L3.DestIP))
return negMatch(anyNetMatch(rule.Match.DestNetN, pkt.L3.DestIP))
}
return result
}
Expand All @@ -108,11 +98,11 @@ func matchSourcePort(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Match
// source port
if rule.Match.SrcPort != nil && len(rule.Match.SrcPort) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("SPort: %v vs %v", rule.Match.SrcPort, pkt.L4.SrcPort))
return ruleMatch(anyPortMatch(rule.Match.SrcPort, pkt.L4.SrcPort))
return anyPortMatch(rule.Match.SrcPort, pkt.L4.SrcPort)
}
if rule.Match.SrcPortN != nil && len(rule.Match.SrcPortN) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!SPort: %v vs %v", rule.Match.SrcPortN, pkt.L4.SrcPort))
return ruleMatch(!anyPortMatch(rule.Match.SrcPortN, pkt.L4.SrcPort))
return negMatch(anyPortMatch(rule.Match.SrcPortN, pkt.L4.SrcPort))
}
return meta.MatchNeutral
}
Expand All @@ -121,73 +111,74 @@ func matchDestinationPort(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.M
// destination port
if rule.Match.DestPort != nil && len(rule.Match.DestPort) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("DPort: %v vs %v", rule.Match.DestPort, pkt.L4.DestPort))
return ruleMatch(anyPortMatch(rule.Match.DestPort, pkt.L4.DestPort))
return anyPortMatch(rule.Match.DestPort, pkt.L4.DestPort)
}
if rule.Match.DestPortN != nil && len(rule.Match.DestPortN) > 0 {
ruleDebug(pkt, rid, fmt.Sprintf("!DPort: %v vs %v", rule.Match.DestPortN, pkt.L4.DestPort))
return ruleMatch(!anyPortMatch(rule.Match.DestPortN, pkt.L4.DestPort))
return negMatch(anyPortMatch(rule.Match.DestPortN, pkt.L4.DestPort))
}
return meta.MatchNeutral
}

func matchDomain(pkt parse.ParsedPacket, rule cnf.Rule, rid int) meta.Match {
if rule.Match.Domains != nil && len(rule.Match.Domains) > 0 {
if pkt.L5.Proto == meta.ProtoL5Tls {
return ruleMatch(anyDomainMatch(rule.Match.Domains, pkt.L5.TlsSni))
return anyDomainMatch(rule.Match.Domains, pkt.L5.TlsSni)
}
// todo: add plain http domain-match
}
return meta.MatchNeutral
}

func anyProtoMatch(list []meta.Proto, single meta.Proto) bool {
func anyProtoMatch(list []meta.Proto, single meta.Proto) meta.Match {
for i := range list {
if list[i] == single {
return true
return meta.MatchPositive
}
}
return false
return meta.MatchNegative
}

func anyPortMatch(list []uint16, single uint16) bool {
func anyPortMatch(list []uint16, single uint16) meta.Match {
for i := range list {
if list[i] == single {
return true
return meta.MatchPositive
}
}
return false
return meta.MatchNegative
}

func anyNetMatch(nets []*net.IPNet, ip net.IP) bool {
func anyNetMatch(nets []*net.IPNet, ip net.IP) meta.Match {
for i := range nets {
if nets[i].Contains(ip) {
return true
return meta.MatchPositive
}
}
return false
return meta.MatchNegative
}

func anyDomainMatch(domains []string, domain string) bool {
func anyDomainMatch(domains []string, domain string) meta.Match {
for i := range domains {
matchDomain := domains[i]
if strings.HasPrefix(matchDomain, "*.") {
matchDomain = strings.Replace(matchDomain, "*.", "", 1)
if strings.HasSuffix(domain, matchDomain) {
return true
return meta.MatchPositive
}
} else {
if matchDomain == domain {
return true
return meta.MatchPositive
}
}
}
return false
return meta.MatchNegative
}

func ruleMatch(match bool) meta.Match {
if match {
return meta.MatchPositive
} else {
func negMatch(match meta.Match) meta.Match {
if match == meta.MatchPositive {
return meta.MatchNegative
} else if match == meta.MatchNegative {
return meta.MatchPositive
}
return meta.MatchNegative
}
28 changes: 14 additions & 14 deletions lib/proc/filter/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,62 +15,62 @@ func testNet(netIn string) *net.IPNet {
}

func TestAnyPortMatch(t *testing.T) {
if !anyPortMatch([]uint16{80, 443}, uint16(80)) {
if anyPortMatch([]uint16{80, 443}, uint16(80)) == meta.MatchNegative {
t.Error("AnyPort #1")
}
if !anyPortMatch([]uint16{389, 34938, 1022}, uint16(34938)) {
if anyPortMatch([]uint16{389, 34938, 1022}, uint16(34938)) == meta.MatchNegative {
t.Error("AnyPort #2")
}
if anyPortMatch([]uint16{389, 34938, 1022}, uint16(20930)) {
if anyPortMatch([]uint16{389, 34938, 1022}, uint16(20930)) == meta.MatchPositive {
t.Error("AnyPort #3")
}
if anyPortMatch([]uint16{65000, 443}, uint16(1000)) {
if anyPortMatch([]uint16{65000, 443}, uint16(1000)) == meta.MatchPositive {
t.Error("AnyPort #3")
}
}

func TestAnyNetMatch(t *testing.T) {
net1 := testNet("192.168.0.0/16")
ip := net.ParseIP("192.168.0.1")
if !anyNetMatch([]*net.IPNet{net1}, ip) {
if anyNetMatch([]*net.IPNet{net1}, ip) == meta.MatchNegative {
t.Error("AnyNet #1")
}
ip = net.ParseIP("192.167.0.1")
if anyNetMatch([]*net.IPNet{net1}, ip) {
if anyNetMatch([]*net.IPNet{net1}, ip) == meta.MatchPositive {
t.Error("AnyNet #2")
}
net2 := testNet("10.0.0.0/8")
ip = net.ParseIP("10.255.0.1")
if !anyNetMatch([]*net.IPNet{net1, net2}, ip) {
if anyNetMatch([]*net.IPNet{net1, net2}, ip) == meta.MatchNegative {
t.Error("AnyNet #3")
}
ip = net.ParseIP("172.16.0.1")
if anyNetMatch([]*net.IPNet{net1, net2}, ip) {
if anyNetMatch([]*net.IPNet{net1, net2}, ip) == meta.MatchPositive {
t.Error("AnyNet #4")
}
net3 := testNet("2001:db8::/80")
ip = net.ParseIP("192.168.251.48")
if !anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) {
if anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) == meta.MatchNegative {
t.Error("AnyNet #5")
}
ip = net.ParseIP("2001:db8::1:9")
if !anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) {
if anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) == meta.MatchNegative {
t.Error("AnyNet #6")
}
ip = net.ParseIP("2002:db8::1:9")
if anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) {
if anyNetMatch([]*net.IPNet{net1, net2, net3}, ip) == meta.MatchPositive {
t.Error("AnyNet #7")
}
}

func TestAnyProtoMatch(t *testing.T) {
if !anyProtoMatch([]meta.Proto{meta.ProtoL4Tcp, meta.ProtoL4Udp}, meta.ProtoL4Udp) {
if anyProtoMatch([]meta.Proto{meta.ProtoL4Tcp, meta.ProtoL4Udp}, meta.ProtoL4Udp) == meta.MatchNegative {
t.Error("AnyProto #1")
}
if anyProtoMatch([]meta.Proto{meta.ProtoL5Dns, meta.ProtoL5Tls}, meta.ProtoL5Http) {
if anyProtoMatch([]meta.Proto{meta.ProtoL5Dns, meta.ProtoL5Tls}, meta.ProtoL5Http) == meta.MatchPositive {
t.Error("AnyProto #2")
}
if anyProtoMatch([]meta.Proto{meta.ProtoL5Tls}, meta.ProtoL5Http) {
if anyProtoMatch([]meta.Proto{meta.ProtoL5Tls}, meta.ProtoL5Http) == meta.MatchPositive {
t.Error("AnyProto #3")
}
}
Expand Down

0 comments on commit 42d6d5a

Please sign in to comment.