Working on portmaster restructure

This commit is contained in:
Daniel
2018-11-29 18:44:31 +01:00
parent be8a1d1739
commit 3990790f17
26 changed files with 351 additions and 263 deletions

View File

@@ -20,8 +20,8 @@ func (d Domains) IsSet() bool {
return false
}
// CheckStatus checks if the given domain is governed in the list of domains and returns whether it is permitted.
func (d Domains) CheckStatus(domain string) (permit, ok bool) {
// Check checks if the given domain is governed in the list of domains and returns whether it is permitted.
func (d Domains) Check(domain string) (permit, ok bool) {
// check for exact domain
dd, ok := d[domain]
if ok {

View File

@@ -7,8 +7,8 @@ import (
"github.com/Safing/portmaster/status"
)
// ProfileFlags are used to quickly add common attributes to profiles
type ProfileFlags map[uint8]uint8
// Flags are used to quickly add common attributes to profiles
type Flags map[uint8]uint8
// Profile Flags
const (
@@ -31,8 +31,8 @@ const (
)
var (
// ErrProfileFlagsParseFailed is returned if a an invalid flag is encountered while parsing
ErrProfileFlagsParseFailed = errors.New("profiles: failed to parse flags")
// ErrFlagsParseFailed is returned if a an invalid flag is encountered while parsing
ErrFlagsParseFailed = errors.New("profiles: failed to parse flags")
sortedFlags = []uint8{
Prompt,
@@ -77,34 +77,33 @@ var (
}
)
// FlagsFromNames creates ProfileFlags from a comma seperated list of flagnames (e.g. "System,Strict,Secure")
// func FlagsFromNames(words []string) (*ProfileFlags, error) {
// var flags ProfileFlags
// FlagsFromNames creates Flags from a comma seperated list of flagnames (e.g. "System,Strict,Secure")
// func FlagsFromNames(words []string) (*Flags, error) {
// var flags Flags
// for _, entry := range words {
// flag, ok := flagIDs[entry]
// if !ok {
// return nil, ErrProfileFlagsParseFailed
// return nil, ErrFlagsParseFailed
// }
// flags = append(flags, flag)
// }
// return &flags, nil
// }
// IsSet returns whether the ProfileFlags object is "set".
func (pf ProfileFlags) IsSet() bool {
if pf != nil {
return true
// Check checks if a flag is set at all and if it's active in the given security level.
func (flags Flags) Check(flag, level uint8) (active bool, ok bool) {
if flags == nil {
return false, false
}
return false
}
// Has checks if a ProfileFlags object has a flag set in the given security level
func (pf ProfileFlags) Has(flag, level uint8) bool {
setting, ok := pf[flag]
if ok && setting&level > 0 {
return true
setting, ok := flags[flag]
if ok {
if setting&level > 0 {
return true, true
}
return false, true
}
return false
return false, false
}
func getLevelMarker(levels, level uint8) string {
@@ -114,11 +113,11 @@ func getLevelMarker(levels, level uint8) string {
return "-"
}
// String return a string representation of ProfileFlags
func (pf ProfileFlags) String() string {
var namedFlags []string
// String return a string representation of Flags
func (flags Flags) String() string {
var markedFlags []string
for _, flag := range sortedFlags {
levels, ok := pf[flag]
levels, ok := flags[flag]
if ok {
s := flagNames[flag]
if levels != status.SecurityLevelsAll {
@@ -126,20 +125,18 @@ func (pf ProfileFlags) String() string {
s += getLevelMarker(levels, status.SecurityLevelSecure)
s += getLevelMarker(levels, status.SecurityLevelFortress)
}
markedFlags = append(markedFlags, s)
}
}
for _, flag := range pf {
namedFlags = append(namedFlags, flagNames[flag])
}
return strings.Join(namedFlags, ", ")
return strings.Join(markedFlags, ", ")
}
// Add adds a flag to the Flags with the given level.
func (pf ProfileFlags) Add(flag, levels uint8) {
pf[flag] = levels
func (flags Flags) Add(flag, levels uint8) {
flags[flag] = levels
}
// Remove removes a flag from the Flags.
func (pf ProfileFlags) Remove(flag uint8) {
delete(pf, flag)
func (flags Flags) Remove(flag uint8) {
delete(flags, flag)
}

View File

@@ -2,6 +2,8 @@ package profile
import (
"testing"
"github.com/Safing/portmaster/status"
)
func TestProfileFlags(t *testing.T) {
@@ -20,6 +22,19 @@ func TestProfileFlags(t *testing.T) {
}
}
testFlags := Flags{
Prompt: status.SecurityLevelsAll,
Internet: status.SecurityLevelsDynamicAndSecure,
LAN: status.SecurityLevelsDynamicAndSecure,
Localhost: status.SecurityLevelsAll,
Related: status.SecurityLevelDynamic,
RequireGate17: status.SecurityLevelsSecureAndFortress,
}
if testFlags.String() != "Prompt, Internet++-, LAN++-, Localhost, Related+--, RequireGate17-++" {
t.Errorf("unexpected output: %s", testFlags.String())
}
// // check Has
// emptyFlags := ProfileFlags{}
// for flag, name := range flagNames {

View File

@@ -9,19 +9,12 @@ import (
// Ports is a list of permitted or denied ports
type Ports map[string][]*Port
// IsSet returns whether the Ports object is "set".
func (p Ports) IsSet() bool {
if p != nil {
return true
}
return false
}
// CheckStatus returns whether listening/connecting to a certain port is allowed, and if this option is even set.
func (p Ports) CheckStatus(listen bool, protocol string, port uint16) (permit, ok bool) {
// 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) {
if p == nil {
return false, false
}
if listen {
protocol = "<" + protocol
}
@@ -33,7 +26,7 @@ func (p Ports) CheckStatus(listen bool, protocol string, port uint16) (permit, o
}
}
}
return false, true
return false, false
}
func (p Ports) String() string {

View File

@@ -29,7 +29,7 @@ type Profile struct {
// The mininum security level to apply to connections made with this profile
SecurityLevel uint8
Flags ProfileFlags
Flags Flags
Domains Domains
Ports Ports
@@ -42,6 +42,7 @@ type Profile struct {
ApproxLastUsed int64
}
// New returns a new Profile.
func New() *Profile {
return &Profile{}
}
@@ -49,12 +50,10 @@ func New() *Profile {
// Save saves the profile to the database
func (profile *Profile) Save(namespace string) error {
if profile.ID == "" {
// FIXME: this is weird, the docs says that it also returns an error
u := uuid.NewV4()
// u, err := uuid.NewV4()
// if err != nil {
// return err
// }
u, err := uuid.NewV4()
if err != nil {
return err
}
profile.ID = u.String()
}

View File

@@ -1,119 +1,132 @@
package profile
import "github.com/Safing/portmaster/status"
var (
emptyFlags = ProfileFlags{}
emptyPorts = Ports{}
emptyFlags = Flags{}
emptyPorts = Ports{}
)
// ProfileSet handles Profile chaining.
type ProfileSet struct {
Profiles [4]*Profile
// Set handles Profile chaining.
type Set struct {
profiles [4]*Profile
// Application
// Global
// Stamp
// Default
Independent bool
securityLevel uint8
independent bool
}
// NewSet returns a new profile set with given the profiles.
func NewSet(user, stamp *Profile) *ProfileSet {
new := &ProfileSet{
Profiles: [4]*Profile{
user, // Application
nil, // Global
func NewSet(user, stamp *Profile) *Set {
new := &Set{
profiles: [4]*Profile{
user, // Application
nil, // Global
stamp, // Stamp
nil, // Default
nil, // Default
},
}
new.Update()
return new
new.Update(status.SecurityLevelFortress)
return new
}
// Update gets the new global and default profile and updates the independence status. It must be called when reusing a profile set for a series of calls.
func (ps *ProfileSet) Update() {
specialProfileLock.RLock()
defer specialProfileLock.RUnlock()
func (set *Set) Update(securityLevel uint8) {
specialProfileLock.RLock()
defer specialProfileLock.RUnlock()
// update profiles
ps.Profiles[1] = globalProfile
ps.Profiles[3] = defaultProfile
// update profiles
set.profiles[1] = globalProfile
set.profiles[3] = defaultProfile
// update independence
if ps.Flags().Has(Independent, ps.SecurityLevel()) {
// Stamp profiles do not have the Independent flag
ps.Independent = true
} else {
ps.Independent = false
}
}
// Flags returns the highest prioritized ProfileFlags configuration.
func (ps *ProfileSet) Flags() ProfileFlags {
for _, profile := range ps.Profiles {
if profile != nil {
if profile.Flags.IsSet() {
return profile.Flags
}
}
// update security level
profileSecurityLevel := set.getProfileSecurityLevel()
if profileSecurityLevel > securityLevel {
set.securityLevel = profileSecurityLevel
} else {
set.securityLevel = securityLevel
}
return emptyFlags
// update independence
if active, ok := set.CheckFlag(Independent); active && ok {
set.independent = true
} else {
set.independent = false
}
}
// CheckDomainStatus checks if the given domain is governed in any the lists of domains and returns whether it is permitted.
func (ps *ProfileSet) CheckDomainStatus(domain string) (permit, ok bool) {
// CheckFlag returns whether a given flag is set.
func (set *Set) CheckFlag(flag) (active bool) {
for i, profile := range ps.Profiles {
if i == 2 && ps.Independent {
continue
}
for i, profile := range set.profiles {
if i == 2 && set.independent {
continue
}
if profile != nil {
if profile.Domains.IsSet() {
permit, ok = profile.Domains.CheckStatus(domain)
if ok {
return
}
}
}
if profile != nil {
active, ok := profile.Flags.Check(flag, set.securityLevel)
if ok {
return active
}
}
}
return false
}
// CheckDomain checks if the given domain is governed in any the lists of domains and returns whether it is permitted.
func (set *Set) CheckDomain(domain string) (permit, ok bool) {
for i, profile := range set.profiles {
if i == 2 && set.independent {
continue
}
if profile != nil {
permit, ok = profile.Domains.Check(domain)
if ok {
return
}
}
}
return false, false
}
// Ports returns the highest prioritized Ports configuration.
func (set *Set) CheckPort() (permit, ok bool) {
for i, profile := range set.profiles {
if i == 2 && set.independent {
continue
}
if profile != nil {
if profile.Ports.Check() {
return profile.Ports
}
}
}
return false, false
}
// Ports returns the highest prioritized Ports configuration.
func (ps *ProfileSet) Ports() Ports {
for i, profile := range ps.Profiles {
if i == 2 && ps.Independent {
continue
}
if profile != nil {
if profile.Ports.IsSet() {
return profile.Ports
}
}
}
return emptyPorts
}
// SecurityLevel returns the highest prioritized security level.
func (ps *ProfileSet) SecurityLevel() uint8 {
func (set *Set) getProfileSecurityLevel() uint8 {
for i, profile := range ps.Profiles {
if i == 2 {
// Stamp profiles do not have the SecurityLevel setting
continue
}
for i, profile := range set.profiles {
if i == 2 {
// Stamp profiles do not have the SecurityLevel setting
continue
}
if profile != nil {
if profile.SecurityLevel > 0 {
return profile.SecurityLevel
}
if profile != nil {
if profile.SecurityLevel > 0 {
return profile.SecurityLevel
}
}
}