Work on portmaster restructuring

This commit is contained in:
Daniel 2018-11-30 22:11:00 +01:00
parent 3990790f17
commit 62b1c03edc
13 changed files with 349 additions and 112 deletions

View file

@ -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)
} }

View 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
View 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
}

View file

@ -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
View 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
}

View file

@ -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])
} }

View file

@ -1,6 +1,6 @@
package profile package profile
// OS Identifier Prefix // OS Identifier
const ( const (
IdentifierPrefix = "mac:" osIdentifier = "mac"
) )

View file

@ -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
View 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) {
//
// }

View file

@ -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 {

View file

@ -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"`

View file

@ -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.

View 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)
}