allow to use lists of md5s to block connections

Besides domains, net ranges and IPs, now it's possible to
filter connections by the MD5 of a binary, if it's enabled.
This commit is contained in:
Gustavo Iñiguez Goia 2025-01-24 00:47:02 +01:00
parent 5184c45086
commit ced8410d43
Failed to generate hash of commit
2 changed files with 76 additions and 47 deletions

View file

@ -15,6 +15,7 @@ import (
"github.com/evilsocket/opensnitch/daemon/conman"
"github.com/evilsocket/opensnitch/daemon/core"
"github.com/evilsocket/opensnitch/daemon/log"
"github.com/evilsocket/opensnitch/daemon/procmon"
)
// Type is the type of rule.
@ -64,8 +65,9 @@ const (
OpDomainsRegexpLists = Operand("lists.domains_regexp")
OpIPLists = Operand("lists.ips")
OpNetLists = Operand("lists.nets")
OpHashMD5Lists = Operand("lists.hash.md5")
// TODO
//OpHashMD5Lists = Operand("lists.hash.md5")
//OpQuota = Operand("quota")
//OpQuotaTxOver = Operand("quota.sent.over") // 1000b, 1kb, 1mb, 1gb, ...
//OpQuotaRxOver = Operand("quota.recv.over") // 1000b, 1kb, 1mb, 1gb, ...
@ -225,7 +227,7 @@ func (o *Operator) Compile() error {
return fmt.Errorf("Operand lists is empty, nothing to load: %s", o)
}
o.loadLists()
o.cb = o.domainsListCmp
o.cb = o.domainsListsCmp
} else if o.Operand == OpDomainsRegexpLists {
if o.Data == "" {
return fmt.Errorf("Operand regexp lists is empty, nothing to load: %s", o)
@ -237,13 +239,19 @@ func (o *Operator) Compile() error {
return fmt.Errorf("Operand ip lists is empty, nothing to load: %s", o)
}
o.loadLists()
o.cb = o.ipListCmp
o.cb = o.simpleListsCmp
} else if o.Operand == OpNetLists {
if o.Data == "" {
return fmt.Errorf("Operand net lists is empty, nothing to load: %s", o)
}
o.loadLists()
o.cb = o.ipNetCmp
} else if o.Operand == OpHashMD5Lists {
if o.Data == "" {
return fmt.Errorf("Operand lists.hash.md5 is empty, nothing to load: %s", o)
}
o.loadLists()
o.cb = o.simpleListsCmp
} else if o.Operand == OpProcessHashMD5 || o.Operand == OpProcessHashSHA1 {
o.cb = o.hashCmp
}
@ -288,7 +296,15 @@ func (o *Operator) cmpNetwork(destIP interface{}) bool {
return o.netMask.Contains(destIP.(net.IP))
}
func (o *Operator) domainsListCmp(v interface{}) bool {
func (o *Operator) matchListsCmp(msg, what string) bool {
if item, found := o.lists[what]; found {
log.Debug("%s: %s, %s", log.Red(msg), what, item)
return true
}
return false
}
func (o *Operator) domainsListsCmp(v interface{}) bool {
dstHost := v.(string)
if dstHost == "" {
return false
@ -299,26 +315,18 @@ func (o *Operator) domainsListCmp(v interface{}) bool {
o.RLock()
defer o.RUnlock()
if _, found := o.lists[dstHost]; found {
log.Debug("%s: %s, %s", log.Red("domain list match"), dstHost, o.lists[dstHost])
return true
}
return false
return o.matchListsCmp("domains list match", dstHost)
}
func (o *Operator) ipListCmp(v interface{}) bool {
dstIP := v.(string)
if dstIP == "" {
func (o *Operator) simpleListsCmp(v interface{}) bool {
what := v.(string)
if what == "" {
return false
}
o.RLock()
defer o.RUnlock()
if _, found := o.lists[dstIP]; found {
log.Debug("%s: %s, %s", log.Red("IP list match"), dstIP, o.lists[dstIP].(string))
return true
}
return false
return o.matchListsCmp("simple list match", what)
}
func (o *Operator) ipNetCmp(dstIP interface{}) bool {
@ -393,6 +401,8 @@ func (o *Operator) Match(con *conman.Connection, hasChecksums bool) bool {
return o.cb(con.DstHost)
} else if o.Operand == OpIPLists {
return o.cb(con.DstIP.String())
} else if o.Operand == OpHashMD5Lists {
return o.cb(con.Process.Checksums[procmon.HashMD5])
} else if o.Operand == OpUserID || o.Operand == OpUserName {
return o.cb(strconv.Itoa(con.Entry.UserId))
} else if o.Operand == OpDstNetwork {

View file

@ -104,32 +104,46 @@ func (o *Operator) StopMonitoringLists() {
}
}
func (o *Operator) readDomainsList(raw, fileName string) (dups uint64) {
log.Debug("Loading domains list: %s, size: %d", fileName, len(raw))
lines := strings.Split(string(raw), "\n")
for _, domain := range lines {
if len(domain) < 9 {
continue
}
// exclude not valid lines
if domain[:7] != "0.0.0.0" && domain[:9] != "127.0.0.1" {
continue
}
host := domain[8:]
// exclude localhost entries
if domain[:9] == "127.0.0.1" {
host = domain[10:]
}
if host == "local" || host == "localhost" || host == "localhost.localdomain" || host == "broadcasthost" {
continue
}
func filterDomains(line, defValue string) (bool, string, string) {
if len(line) < 9 {
return true, line, defValue
}
// exclude not valid lines
if line[:7] != "0.0.0.0" && line[:9] != "127.0.0.1" {
return true, line, defValue
}
host := line[8:]
// exclude localhost entries
if line[:9] == "127.0.0.1" {
host = line[10:]
}
if host == "local" || host == "localhost" || host == "localhost.localdomain" || host == "broadcasthost" {
return true, line, defValue
}
host = core.Trim(host)
if _, found := o.lists[host]; found {
return false, host, defValue
}
func filterSimple(line, hashPath string) (bool, string, string) {
// XXX: some lists may use TABs as separator
hash := strings.SplitN(line, " ", 2)
return false, hash[0], hash[1]
}
func (o *Operator) readTupleList(raw, fileName string, filter func(line, defValue string) (bool, string, string)) (dups uint64) {
log.Debug("Loading list: %s, size: %d", fileName, len(raw))
lines := strings.Split(string(raw), "\n")
for _, line := range lines {
skip, key, value := filter(line, fileName)
if skip || len(line) < 9 {
continue
}
key = core.Trim(key)
if _, found := o.lists[key]; found {
dups++
continue
}
o.lists[host] = fileName
o.lists[key] = value
}
lines = nil
log.Info("%d domains loaded, %s", len(o.lists), fileName)
@ -187,22 +201,25 @@ func (o *Operator) readRegexpList(raw, fileName string) (dups uint64) {
return dups
}
func (o *Operator) readIPList(raw, fileName string) (dups uint64) {
log.Debug("Loading IPs list: %s, size: %d", fileName, len(raw))
// A simple list is a list composed of one column with several entries, that
// don't require manipulation.
// It can be a list of IPs, domains, etc.
func (o *Operator) readSimpleList(raw, fileName string) (dups uint64) {
log.Debug("Loading simple list: %s, size: %d", fileName, len(raw))
lines := strings.Split(string(raw), "\n")
for _, line := range lines {
if line == "" || line[0] == '#' {
continue
}
ip := core.Trim(line)
if _, found := o.lists[ip]; found {
what := core.Trim(line)
if _, found := o.lists[what]; found {
dups++
continue
}
o.lists[ip] = fileName
o.lists[what] = fileName
}
lines = nil
log.Info("%d IPs loaded, %s", len(o.lists), fileName)
log.Info("%d entries loaded, %s", len(o.lists), fileName)
return dups
}
@ -236,13 +253,15 @@ func (o *Operator) readLists() error {
}
if o.Operand == OpDomainsLists {
dups += o.readDomainsList(string(raw), fileName)
dups += o.readTupleList(string(raw), fileName, filterDomains)
} else if o.Operand == OpDomainsRegexpLists {
dups += o.readRegexpList(string(raw), fileName)
} else if o.Operand == OpNetLists {
dups += o.readNetList(string(raw), fileName)
} else if o.Operand == OpIPLists {
dups += o.readIPList(string(raw), fileName)
dups += o.readSimpleList(string(raw), fileName)
} else if o.Operand == OpHashMD5Lists {
dups += o.readSimpleList(string(raw), fileName)
} else {
log.Warning("Unknown lists operand type: %s", o.Operand)
}