mirror of
https://github.com/safing/portmaster
synced 2025-09-04 11:39:29 +00:00
Work on portmaster restructuring
This commit is contained in:
parent
3990790f17
commit
62b1c03edc
13 changed files with 349 additions and 112 deletions
|
@ -34,40 +34,40 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
|
|
||||||
// grant self
|
// grant self
|
||||||
if connection.Process().Pid == os.Getpid() {
|
if connection.Process().Pid == os.Getpid() {
|
||||||
log.Infof("sheriff: granting own connection %s", connection)
|
log.Infof("firewall: granting own connection %s", connection)
|
||||||
connection.Accept()
|
connection.Accept()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profile := connection.Process().Profile
|
profileSet := connection.Process().ProfileSetSet
|
||||||
if profile == nil {
|
if profile == nil {
|
||||||
log.Infof("sheriff: no profile, denying connection %s", connection)
|
log.Infof("firewall: no profile, denying connection %s", connection)
|
||||||
connection.AddReason("no profile")
|
connection.AddReason("no profile")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check user class
|
// check user class
|
||||||
if profile.Flags.Has(profile.System) {
|
if profileSet.CheckFlag(profile.System) {
|
||||||
if !connection.Process().IsSystem() {
|
if !connection.Process().IsSystem() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has System flag set, but process is not executed by System", connection)
|
log.Infof("firewall: denying connection %s, profile has System flag set, but process is not executed by System", connection)
|
||||||
connection.AddReason("must be executed by system")
|
connection.AddReason("must be executed by system")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if profile.Flags.Has(profile.Admin) {
|
if profileSet.CheckFlag(profile.Admin) {
|
||||||
if !connection.Process().IsAdmin() {
|
if !connection.Process().IsAdmin() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has Admin flag set, but process is not executed by Admin", connection)
|
log.Infof("firewall: denying connection %s, profile has Admin flag set, but process is not executed by Admin", connection)
|
||||||
connection.AddReason("must be executed by admin")
|
connection.AddReason("must be executed by admin")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if profile.Flags.Has(profile.User) {
|
if profileSet.CheckFlag(profile.User) {
|
||||||
if !connection.Process().IsUser() {
|
if !connection.Process().IsUser() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has User flag set, but process is not executed by a User", connection)
|
log.Infof("firewall: denying connection %s, profile has User flag set, but process is not executed by a User", connection)
|
||||||
connection.AddReason("must be executed by user")
|
connection.AddReason("must be executed by user")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
|
@ -75,8 +75,8 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for any network access
|
// check for any network access
|
||||||
if !profile.Flags.Has(profile.Internet) && !profile.Flags.Has(profile.LocalNet) {
|
if !profileSet.CheckFlag(profile.Internet) && !profileSet.CheckFlag(profile.LocalNet) {
|
||||||
log.Infof("sheriff: denying connection %s, profile denies Internet and local network access", connection)
|
log.Infof("firewall: denying connection %s, profile denies Internet and local network access", connection)
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -102,14 +102,14 @@ func DecideOnConnectionBeforeIntel(connection *network.Connection, fqdn string)
|
||||||
}
|
}
|
||||||
if matched {
|
if matched {
|
||||||
if profile.DomainWhitelistIsBlacklist {
|
if profile.DomainWhitelistIsBlacklist {
|
||||||
log.Infof("sheriff: denying connection %s, profile has %s in domain blacklist", connection, fqdn)
|
log.Infof("firewall: denying connection %s, profile has %s in domain blacklist", connection, fqdn)
|
||||||
connection.AddReason("domain blacklisted")
|
connection.AddReason("domain blacklisted")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !profile.DomainWhitelistIsBlacklist {
|
if !profile.DomainWhitelistIsBlacklist {
|
||||||
log.Infof("sheriff: denying connection %s, profile does not have %s in domain whitelist", connection, fqdn)
|
log.Infof("firewall: denying connection %s, profile does not have %s in domain whitelist", connection, fqdn)
|
||||||
connection.AddReason("domain not in whitelist")
|
connection.AddReason("domain not in whitelist")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
|
@ -127,9 +127,10 @@ func DecideOnConnectionAfterIntel(connection *network.Connection, fqdn string, r
|
||||||
// - network specific: Strict
|
// - network specific: Strict
|
||||||
|
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profile := connection.Process().Profile
|
profileSet := connection.Process().ProfileSet
|
||||||
if profile == nil {
|
// FIXME: there should always be a profile
|
||||||
log.Infof("sheriff: no profile, denying connection %s", connection)
|
if profileSet == nil {
|
||||||
|
log.Infof("firewall: no profile, denying connection %s", connection)
|
||||||
connection.AddReason("no profile")
|
connection.AddReason("no profile")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return rrCache
|
return rrCache
|
||||||
|
@ -137,7 +138,7 @@ func DecideOnConnectionAfterIntel(connection *network.Connection, fqdn string, r
|
||||||
|
|
||||||
// check Strict flag
|
// check Strict flag
|
||||||
// TODO: drastically improve this!
|
// TODO: drastically improve this!
|
||||||
if profile.Flags.Has(profile.Strict) {
|
if profileSet.CheckFlag(profile.Related) {
|
||||||
matched := false
|
matched := false
|
||||||
pathElements := strings.Split(connection.Process().Path, "/")
|
pathElements := strings.Split(connection.Process().Path, "/")
|
||||||
if len(pathElements) > 2 {
|
if len(pathElements) > 2 {
|
||||||
|
@ -162,7 +163,7 @@ func DecideOnConnectionAfterIntel(connection *network.Connection, fqdn string, r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !matched {
|
if !matched {
|
||||||
log.Infof("sheriff: denying connection %s, profile has declared Strict flag and no match to domain was found", connection)
|
log.Infof("firewall: denying connection %s, profile has declared Strict flag and no match to domain was found", connection)
|
||||||
connection.AddReason("domain does not relate to process")
|
connection.AddReason("domain does not relate to process")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return rrCache
|
return rrCache
|
||||||
|
@ -195,40 +196,40 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) {
|
||||||
|
|
||||||
// grant self
|
// grant self
|
||||||
if connection.Process().Pid == os.Getpid() {
|
if connection.Process().Pid == os.Getpid() {
|
||||||
log.Infof("sheriff: granting own connection %s", connection)
|
log.Infof("firewall: granting own connection %s", connection)
|
||||||
connection.Accept()
|
connection.Accept()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profile := connection.Process().Profile
|
profileSet := connection.Process().ProfileSet
|
||||||
if profile == nil {
|
if profile == nil {
|
||||||
log.Infof("sheriff: no profile, denying connection %s", connection)
|
log.Infof("firewall: no profile, denying connection %s", connection)
|
||||||
connection.AddReason("no profile")
|
connection.AddReason("no profile")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check user class
|
// check user class
|
||||||
if profile.Flags.Has(profile.System) {
|
if profileSet.CheckFlag(profile.System) {
|
||||||
if !connection.Process().IsSystem() {
|
if !connection.Process().IsSystem() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has System flag set, but process is not executed by System", connection)
|
log.Infof("firewall: denying connection %s, profile has System flag set, but process is not executed by System", connection)
|
||||||
connection.AddReason("must be executed by system")
|
connection.AddReason("must be executed by system")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if profile.Flags.Has(profile.Admin) {
|
if profileSet.CheckFlag(profile.Admin) {
|
||||||
if !connection.Process().IsAdmin() {
|
if !connection.Process().IsAdmin() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has Admin flag set, but process is not executed by Admin", connection)
|
log.Infof("firewall: denying connection %s, profile has Admin flag set, but process is not executed by Admin", connection)
|
||||||
connection.AddReason("must be executed by admin")
|
connection.AddReason("must be executed by admin")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if profile.Flags.Has(profile.User) {
|
if profileSet.CheckFlag(profile.User) {
|
||||||
if !connection.Process().IsUser() {
|
if !connection.Process().IsUser() {
|
||||||
log.Infof("sheriff: denying connection %s, profile has User flag set, but process is not executed by a User", connection)
|
log.Infof("firewall: denying connection %s, profile has User flag set, but process is not executed by a User", connection)
|
||||||
connection.AddReason("must be executed by user")
|
connection.AddReason("must be executed by user")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
|
@ -236,8 +237,8 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for any network access
|
// check for any network access
|
||||||
if !profile.Flags.Has(profile.Internet) && !profile.Flags.Has(profile.LocalNet) {
|
if !profileSet.CheckFlag(profile.Internet) && !profileSet.CheckFlag(profile.LocalNet) {
|
||||||
log.Infof("sheriff: denying connection %s, profile denies Internet and local network access", connection)
|
log.Infof("firewall: denying connection %s, profile denies Internet and local network access", connection)
|
||||||
connection.AddReason("no network access allowed")
|
connection.AddReason("no network access allowed")
|
||||||
connection.Block()
|
connection.Block()
|
||||||
return
|
return
|
||||||
|
@ -246,29 +247,29 @@ func DecideOnConnection(connection *network.Connection, pkt packet.Packet) {
|
||||||
switch connection.Domain {
|
switch connection.Domain {
|
||||||
case "I":
|
case "I":
|
||||||
// check Service flag
|
// check Service flag
|
||||||
if !profile.Flags.Has(profile.Service) {
|
if !profileSet.CheckFlag(profile.Service) {
|
||||||
log.Infof("sheriff: denying connection %s, profile does not declare service", connection)
|
log.Infof("firewall: denying connection %s, profile does not declare service", connection)
|
||||||
connection.AddReason("not a service")
|
connection.AddReason("not a service")
|
||||||
connection.Drop()
|
connection.Drop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check if incoming connections are allowed on any port, but only if there no other restrictions
|
// check if incoming connections are allowed on any port, but only if there no other restrictions
|
||||||
if !!profile.Flags.Has(profile.Internet) && !!profile.Flags.Has(profile.LocalNet) && len(profile.ListenPorts) == 0 {
|
if !!profileSet.CheckFlag(profile.Internet) && !!profileSet.CheckFlag(profile.LocalNet) && len(profile.ListenPorts) == 0 {
|
||||||
log.Infof("sheriff: granting connection %s, profile allows incoming connections from anywhere and on any port", connection)
|
log.Infof("firewall: granting connection %s, profile allows incoming connections from anywhere and on any port", connection)
|
||||||
connection.Accept()
|
connection.Accept()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "D":
|
case "D":
|
||||||
// check Directconnect flag
|
// check PeerToPeer flag
|
||||||
if !profile.Flags.Has(profile.Directconnect) {
|
if !profileSet.CheckFlag(profile.PeerToPeer) {
|
||||||
log.Infof("sheriff: denying connection %s, profile does not declare direct connections", connection)
|
log.Infof("firewall: denying connection %s, profile does not declare direct connections", connection)
|
||||||
connection.AddReason("direct connections (without DNS) not allowed")
|
connection.AddReason("direct connections (without DNS) not allowed")
|
||||||
connection.Drop()
|
connection.Drop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("sheriff: could not decide on connection %s, deciding on per-link basis", connection)
|
log.Infof("firewall: could not decide on connection %s, deciding on per-link basis", connection)
|
||||||
connection.CantSay()
|
connection.CantSay()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,9 +281,9 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
// Profile.ListenPorts
|
// Profile.ListenPorts
|
||||||
|
|
||||||
// check if there is a profile
|
// check if there is a profile
|
||||||
profile := connection.Process().Profile
|
profileSet := connection.Process().ProfileSet
|
||||||
if profile == nil {
|
if profile == nil {
|
||||||
log.Infof("sheriff: no profile, denying %s", link)
|
log.Infof("firewall: no profile, denying %s", link)
|
||||||
link.AddReason("no profile")
|
link.AddReason("no profile")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
|
@ -296,15 +297,15 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
remoteIP = pkt.GetIPHeader().Dst
|
remoteIP = pkt.GetIPHeader().Dst
|
||||||
}
|
}
|
||||||
if netutils.IPIsLocal(remoteIP) {
|
if netutils.IPIsLocal(remoteIP) {
|
||||||
if !profile.Flags.Has(profile.LocalNet) {
|
if !profileSet.CheckFlag(profile.LocalNet) {
|
||||||
log.Infof("sheriff: dropping link %s, profile does not allow communication in the local network", link)
|
log.Infof("firewall: dropping link %s, profile does not allow communication in the local network", link)
|
||||||
link.AddReason("profile does not allow access to local network")
|
link.AddReason("profile does not allow access to local network")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !profile.Flags.Has(profile.Internet) {
|
if !profileSet.CheckFlag(profile.Internet) {
|
||||||
log.Infof("sheriff: dropping link %s, profile does not allow communication with the Internet", link)
|
log.Infof("firewall: dropping link %s, profile does not allow communication with the Internet", link)
|
||||||
link.AddReason("profile does not allow access to the Internet")
|
link.AddReason("profile does not allow access to the Internet")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
|
@ -316,7 +317,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
|
|
||||||
tcpUdpHeader := pkt.GetTCPUDPHeader()
|
tcpUdpHeader := pkt.GetTCPUDPHeader()
|
||||||
if tcpUdpHeader == nil {
|
if tcpUdpHeader == nil {
|
||||||
log.Infof("sheriff: blocking link %s, profile has declared connect port whitelist, but link is not TCP/UDP", link)
|
log.Infof("firewall: blocking link %s, profile has declared connect port whitelist, but link is not TCP/UDP", link)
|
||||||
link.AddReason("profile has declared connect port whitelist, but link is not TCP/UDP")
|
link.AddReason("profile has declared connect port whitelist, but link is not TCP/UDP")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
|
@ -339,7 +340,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matched {
|
if !matched {
|
||||||
log.Infof("sheriff: blocking link %s, remote port %d not in profile connect port whitelist", link, remotePort)
|
log.Infof("firewall: blocking link %s, remote port %d not in profile connect port whitelist", link, remotePort)
|
||||||
link.AddReason("destination port not in whitelist")
|
link.AddReason("destination port not in whitelist")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
|
@ -352,7 +353,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
|
|
||||||
tcpUdpHeader := pkt.GetTCPUDPHeader()
|
tcpUdpHeader := pkt.GetTCPUDPHeader()
|
||||||
if tcpUdpHeader == nil {
|
if tcpUdpHeader == nil {
|
||||||
log.Infof("sheriff: dropping link %s, profile has declared listen port whitelist, but link is not TCP/UDP", link)
|
log.Infof("firewall: dropping link %s, profile has declared listen port whitelist, but link is not TCP/UDP", link)
|
||||||
link.AddReason("profile has declared listen port whitelist, but link is not TCP/UDP")
|
link.AddReason("profile has declared listen port whitelist, but link is not TCP/UDP")
|
||||||
link.UpdateVerdict(network.DROP)
|
link.UpdateVerdict(network.DROP)
|
||||||
return
|
return
|
||||||
|
@ -375,7 +376,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matched {
|
if !matched {
|
||||||
log.Infof("sheriff: blocking link %s, local port %d not in profile listen port whitelist", link, localPort)
|
log.Infof("firewall: blocking link %s, local port %d not in profile listen port whitelist", link, localPort)
|
||||||
link.AddReason("listen port not in whitelist")
|
link.AddReason("listen port not in whitelist")
|
||||||
link.UpdateVerdict(network.BLOCK)
|
link.UpdateVerdict(network.BLOCK)
|
||||||
return
|
return
|
||||||
|
@ -383,7 +384,7 @@ func DecideOnLink(connection *network.Connection, link *network.Link, pkt packet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("sheriff: accepting link %s", link)
|
log.Infof("firewall: accepting link %s", link)
|
||||||
link.UpdateVerdict(network.ACCEPT)
|
link.UpdateVerdict(network.ACCEPT)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
43
network/reference/protocols.go
Normal file
43
network/reference/protocols.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package reference
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
var (
|
||||||
|
protocolNames = map[uint8]string{
|
||||||
|
1: "ICMP",
|
||||||
|
2: "IGMP",
|
||||||
|
6: "TCP",
|
||||||
|
17: "UDP",
|
||||||
|
27: "RDP",
|
||||||
|
33: "DCCP",
|
||||||
|
136: "UDPLite",
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolNumbers = map[string]uint8{
|
||||||
|
"ICMP": 1,
|
||||||
|
"IGMP": 2,
|
||||||
|
"TCP": 6,
|
||||||
|
"UDP": 17,
|
||||||
|
"RDP": 27,
|
||||||
|
"DCCP": 33,
|
||||||
|
"UDPLite": 136,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetProtocolName returns the name of a IP protocol number.
|
||||||
|
func GetProtocolName(protocol uint8) (name string) {
|
||||||
|
name, ok := protocolNames[protocol]
|
||||||
|
if ok {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return strconv.Itoa(int(protocol))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProtocolNumber returns the number of a IP protocol name.
|
||||||
|
func GetProtocolNumber(protocol string) (number uint8, ok bool) {
|
||||||
|
number, ok = protocolNumbers[protocol]
|
||||||
|
if ok {
|
||||||
|
return number, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
43
process/executable.go
Normal file
43
process/executable.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"encoding/hex"
|
||||||
|
"hash"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetExecHash returns the hash of the executable with the given algorithm.
|
||||||
|
func (p *Process) GetExecHash(algorithm string) (string, error) {
|
||||||
|
sum, ok := p.ExecHashes[algorithm]
|
||||||
|
if ok {
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasher hash.Hash
|
||||||
|
switch algorithm {
|
||||||
|
case "md5":
|
||||||
|
hasher = crypto.MD5.New()
|
||||||
|
case "sha1":
|
||||||
|
hasher = crypto.SHA1.New()
|
||||||
|
case "sha256":
|
||||||
|
hasher = crypto.SHA256.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(p.Path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(hasher, file)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
p.ExecHashes[algorithm] = sum
|
||||||
|
return sum, nil
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package process
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Safing/portbase/database/record"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExecutableSignature stores a signature of an executable.
|
|
||||||
type ExecutableSignature []byte
|
|
||||||
|
|
||||||
// FileInfo stores (security) information about a file.
|
|
||||||
type FileInfo struct {
|
|
||||||
record.Base
|
|
||||||
sync.Mutex
|
|
||||||
|
|
||||||
HumanName string
|
|
||||||
Owners []string
|
|
||||||
ApproxLastSeen int64
|
|
||||||
Signature *ExecutableSignature
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFileInfo gathers information about a file and returns *FileInfo
|
|
||||||
func GetFileInfo(path string) *FileInfo {
|
|
||||||
// TODO: actually get file information
|
|
||||||
// TODO: try to load from DB
|
|
||||||
// TODO: save to DB (key: hash of some sorts)
|
|
||||||
splittedPath := strings.Split("/", path)
|
|
||||||
return &FileInfo{
|
|
||||||
HumanName: splittedPath[len(splittedPath)-1],
|
|
||||||
ApproxLastSeen: time.Now().Unix(),
|
|
||||||
}
|
|
||||||
}
|
|
51
process/matching.go
Normal file
51
process/matching.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Safing/portbase/log"
|
||||||
|
"github.com/Safing/portmaster/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindProfiles finds and assigns a profile set to the process.
|
||||||
|
func (p *Process) FindProfiles() {
|
||||||
|
|
||||||
|
// Get fingerprints of process
|
||||||
|
|
||||||
|
// Check if user profile already exists, else create new
|
||||||
|
|
||||||
|
// Find/Re-evaluate Stamp profile
|
||||||
|
|
||||||
|
// p.UserProfileKey
|
||||||
|
// p.profileSet
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchProfile(p *Process, prof *profile.Profile) (score int) {
|
||||||
|
for _, fp := range prof.Fingerprints {
|
||||||
|
score += matchFingerprint(p, fp)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFingerprint(p *Process, fp *profile.Fingerprint) (score int) {
|
||||||
|
if !fp.MatchesOS() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fp.Type {
|
||||||
|
case "full_path":
|
||||||
|
if p.Path == fp.Value {
|
||||||
|
}
|
||||||
|
return profile.GetFingerprintWeight(fp.Type)
|
||||||
|
case "partial_path":
|
||||||
|
return profile.GetFingerprintWeight(fp.Type)
|
||||||
|
case "md5_sum", "sha1_sum", "sha256_sum":
|
||||||
|
sum, err := p.GetExecHash(fp.Type)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("process: failed to get hash of executable: %s", err)
|
||||||
|
} else if sum == fp.Value {
|
||||||
|
return profile.GetFingerprintWeight(fp.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ package process
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -27,13 +28,18 @@ type Process struct {
|
||||||
ParentPid int
|
ParentPid int
|
||||||
Path string
|
Path string
|
||||||
Cwd string
|
Cwd string
|
||||||
FileInfo *FileInfo
|
|
||||||
CmdLine string
|
CmdLine string
|
||||||
FirstArg string
|
FirstArg string
|
||||||
|
|
||||||
profileSet *profile.Set
|
ExecName string
|
||||||
Name string
|
ExecHashes map[string]string
|
||||||
Icon string
|
// ExecOwner ...
|
||||||
|
// ExecSignature ...
|
||||||
|
|
||||||
|
UserProfileKey string
|
||||||
|
profileSet *profile.Set
|
||||||
|
Name string
|
||||||
|
Icon string
|
||||||
// Icon is a path to the icon and is either prefixed "f:" for filepath, "d:" for database cache path or "c:"/"a:" for a the icon key to fetch it from a company / authoritative node and cache it in its own cache.
|
// Icon is a path to the icon and is either prefixed "f:" for filepath, "d:" for database cache path or "c:"/"a:" for a the icon key to fetch it from a company / authoritative node and cache it in its own cache.
|
||||||
|
|
||||||
FirstConnectionEstablished int64
|
FirstConnectionEstablished int64
|
||||||
|
@ -226,8 +232,11 @@ func GetOrFindProcess(pid int) (*Process, error) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// get FileInfo
|
// Executable Information
|
||||||
new.FileInfo = GetFileInfo(new.Path)
|
|
||||||
|
// FIXME: use os specific path seperator
|
||||||
|
splittedPath := strings.Split("/", new.Path)
|
||||||
|
new.ExecName = strings.ToTitle(splittedPath[len(splittedPath)-1])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package profile
|
package profile
|
||||||
|
|
||||||
// OS Identifier Prefix
|
// OS Identifier
|
||||||
const (
|
const (
|
||||||
IdentifierPrefix = "mac:"
|
osIdentifier = "mac"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package profile
|
package profile
|
||||||
|
|
||||||
// OS Identifier Prefix
|
// OS Identifier
|
||||||
const (
|
const (
|
||||||
IdentifierPrefix = "lin:"
|
osIdentifier = "lin"
|
||||||
)
|
)
|
||||||
|
|
99
profile/fingerprint.go
Normal file
99
profile/fingerprint.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package profile
|
||||||
|
|
||||||
|
var (
|
||||||
|
fingerprintWeights = map[string]int{
|
||||||
|
"full_path": 2,
|
||||||
|
"partial_path": 1,
|
||||||
|
"md5_sum": 4,
|
||||||
|
"sha1_sum": 5,
|
||||||
|
"sha256_sum": 6,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Fingerprint struct {
|
||||||
|
OS string
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fp *Fingerprint) MatchesOS() bool {
|
||||||
|
return fp.OS == osIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// func (fp *Fingerprint) Equals(other *Fingerprint) bool {
|
||||||
|
// return fp.OS == other.OS &&
|
||||||
|
// fp.Type == other.Type &&
|
||||||
|
// fp.Value == other.Value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (fp *Fingerprint) Check(type, value string) (weight int) {
|
||||||
|
// if fp.Match(fpType, value) {
|
||||||
|
// return GetFingerprintWeight(fpType)
|
||||||
|
// }
|
||||||
|
// return 0
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (fp *Fingerprint) Match(fpType, value string) (matches bool) {
|
||||||
|
// switch fp.Type {
|
||||||
|
// case "partial_path":
|
||||||
|
// return
|
||||||
|
// default:
|
||||||
|
// return fp.OS == osIdentifier &&
|
||||||
|
// fp.Type == fpType &&
|
||||||
|
// fp.Value == value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func GetFingerprintWeight(fpType string) (weight int) {
|
||||||
|
weight, ok := fingerprintWeights[fpType]
|
||||||
|
if ok {
|
||||||
|
return weight
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// func (p *Profile) GetApplicableFingerprints() (fingerprints []*Fingerprint) {
|
||||||
|
// for _, fp := range p.Fingerprints {
|
||||||
|
// if fp.OS == osIdentifier {
|
||||||
|
// fingerprints = append(fingerprints, fp)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (p *Profile) AddFingerprint(fp *Fingerprint) error {
|
||||||
|
// if fp.OS == "" {
|
||||||
|
// fp.OS = osIdentifier
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// p.Fingerprints = append(p.Fingerprints, fp)
|
||||||
|
// return p.Save()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (p *Profile) GetApplicableFingerprintTypes() (types []string) {
|
||||||
|
// for _, fp := range p.Fingerprints {
|
||||||
|
// if fp.OS == osIdentifier && !utils.StringInSlice(types, fp.Type) {
|
||||||
|
// types = append(types, fp.Type)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (p *Profile) MatchFingerprints(fingerprints map[string]string) (score int) {
|
||||||
|
// for _, fp := range p.Fingerprints {
|
||||||
|
// if fp.OS == osIdentifier {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func FindUserProfiles() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func FindProfiles(path string) (*ProfileSet, error) {
|
||||||
|
//
|
||||||
|
// }
|
|
@ -4,21 +4,20 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Safing/portmaster/network/reference"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ports is a list of permitted or denied ports
|
// Ports is a list of permitted or denied ports
|
||||||
type Ports map[string][]*Port
|
type Ports map[int16][]*Port
|
||||||
|
|
||||||
// Check returns whether listening/connecting to a certain port is allowed, if set.
|
// Check returns whether listening/connecting to a certain port is allowed, if set.
|
||||||
func (p Ports) Check(listen bool, protocol string, port uint16) (permit, ok bool) {
|
func (p Ports) Check(signedProtocol int16, port uint16) (permit, ok bool) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listen {
|
portDefinitions, ok := p[signedProtocol]
|
||||||
protocol = "<" + protocol
|
|
||||||
}
|
|
||||||
portDefinitions, ok := p[protocol]
|
|
||||||
if ok {
|
if ok {
|
||||||
for _, portD := range portDefinitions {
|
for _, portD := range portDefinitions {
|
||||||
if portD.Matches(port) {
|
if portD.Matches(port) {
|
||||||
|
@ -29,16 +28,23 @@ func (p Ports) Check(listen bool, protocol string, port uint16) (permit, ok bool
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatSignedProtocol(sP int16) string {
|
||||||
|
if sP < 0 {
|
||||||
|
return fmt.Sprintf("<%s", reference.GetProtocolName(uint8(-1*sP)))
|
||||||
|
}
|
||||||
|
return reference.GetProtocolName(uint8(sP))
|
||||||
|
}
|
||||||
|
|
||||||
func (p Ports) String() string {
|
func (p Ports) String() string {
|
||||||
var s []string
|
var s []string
|
||||||
|
|
||||||
for protocol, ports := range p {
|
for signedProtocol, ports := range p {
|
||||||
var portStrings []string
|
var portStrings []string
|
||||||
for _, port := range ports {
|
for _, port := range ports {
|
||||||
portStrings = append(portStrings, port.String())
|
portStrings = append(portStrings, port.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
s = append(s, fmt.Sprintf("%s:[%s]", protocol, strings.Join(portStrings, ", ")))
|
s = append(s, fmt.Sprintf("%s:[%s]", formatSignedProtocol(signedProtocol), strings.Join(portStrings, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
|
|
|
@ -23,8 +23,7 @@ type Profile struct {
|
||||||
// Icon is a path to the icon and is either prefixed "f:" for filepath, "d:" for a database path or "e:" for the encoded data.
|
// Icon is a path to the icon and is either prefixed "f:" for filepath, "d:" for a database path or "e:" for the encoded data.
|
||||||
Icon string
|
Icon string
|
||||||
|
|
||||||
// Identification
|
// Fingerprints
|
||||||
Identifiers []string
|
|
||||||
Fingerprints []string
|
Fingerprints []string
|
||||||
|
|
||||||
// The mininum security level to apply to connections made with this profile
|
// The mininum security level to apply to connections made with this profile
|
||||||
|
@ -33,7 +32,8 @@ type Profile struct {
|
||||||
Domains Domains
|
Domains Domains
|
||||||
Ports Ports
|
Ports Ports
|
||||||
|
|
||||||
StampProfileKey string
|
StampProfileKey string
|
||||||
|
StampProfileAssigned int64
|
||||||
|
|
||||||
// If a Profile is declared as a Framework (i.e. an Interpreter and the likes), then the real process must be found
|
// If a Profile is declared as a Framework (i.e. an Interpreter and the likes), then the real process must be found
|
||||||
// Framework *Framework `json:",omitempty bson:",omitempty"`
|
// Framework *Framework `json:",omitempty bson:",omitempty"`
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (set *Set) Update(securityLevel uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update independence
|
// update independence
|
||||||
if active, ok := set.CheckFlag(Independent); active && ok {
|
if set.CheckFlag(Independent) {
|
||||||
set.independent = true
|
set.independent = true
|
||||||
} else {
|
} else {
|
||||||
set.independent = false
|
set.independent = false
|
||||||
|
@ -59,7 +59,7 @@ func (set *Set) Update(securityLevel uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckFlag returns whether a given flag is set.
|
// CheckFlag returns whether a given flag is set.
|
||||||
func (set *Set) CheckFlag(flag) (active bool) {
|
func (set *Set) CheckFlag(flag uint8) (active bool) {
|
||||||
|
|
||||||
for i, profile := range set.profiles {
|
for i, profile := range set.profiles {
|
||||||
if i == 2 && set.independent {
|
if i == 2 && set.independent {
|
||||||
|
@ -97,7 +97,12 @@ func (set *Set) CheckDomain(domain string) (permit, ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ports returns the highest prioritized Ports configuration.
|
// Ports returns the highest prioritized Ports configuration.
|
||||||
func (set *Set) CheckPort() (permit, ok bool) {
|
func (set *Set) CheckPort(listen bool, protocol uint8, port uint16) (permit, ok bool) {
|
||||||
|
|
||||||
|
signedProtocol := int16(protocol)
|
||||||
|
if listen {
|
||||||
|
signedProtocol = -1 * signedProtocol
|
||||||
|
}
|
||||||
|
|
||||||
for i, profile := range set.profiles {
|
for i, profile := range set.profiles {
|
||||||
if i == 2 && set.independent {
|
if i == 2 && set.independent {
|
||||||
|
@ -105,13 +110,13 @@ func (set *Set) CheckPort() (permit, ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
if profile.Ports.Check() {
|
if permit, ok = profile.Ports.Check(signedProtocol, port); ok {
|
||||||
return profile.Ports
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecurityLevel returns the highest prioritized security level.
|
// SecurityLevel returns the highest prioritized security level.
|
||||||
|
|
17
profile/profileset_test.go
Normal file
17
profile/profileset_test.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package profile
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestProfileSet(t *testing.T) {
|
||||||
|
|
||||||
|
// new := &Set{
|
||||||
|
// profiles: [4]*Profile{
|
||||||
|
// user, // Application
|
||||||
|
// nil, // Global
|
||||||
|
// stamp, // Stamp
|
||||||
|
// nil, // Default
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// new.Update(status.SecurityLevelFortress)
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue