mirror of
https://github.com/evilsocket/opensnitch.git
synced 2025-03-04 08:34:40 +01:00

- Send errors to the server (GUI) if there's any error when reloading the system fw rules (far from being perfect/optimal, needs a rewrite). - Don't load the configuration after saving it, let the watcher reload it on write change to avoid double reload/duplicated errors.
180 lines
4.8 KiB
Go
180 lines
4.8 KiB
Go
package nftables
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/firewall/config"
|
|
"github.com/evilsocket/opensnitch/daemon/firewall/iptables"
|
|
"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
|
|
"github.com/evilsocket/opensnitch/daemon/log"
|
|
"github.com/google/nftables"
|
|
"github.com/google/nftables/expr"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// store of tables added to the system
|
|
type sysTablesT struct {
|
|
tables map[string]*nftables.Table
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (t *sysTablesT) Add(name string, tbl *nftables.Table) {
|
|
t.Lock()
|
|
defer t.Unlock()
|
|
t.tables[name] = tbl
|
|
}
|
|
|
|
func (t *sysTablesT) Get(name string) *nftables.Table {
|
|
t.RLock()
|
|
defer t.RUnlock()
|
|
return t.tables[name]
|
|
}
|
|
|
|
func (t *sysTablesT) List() map[string]*nftables.Table {
|
|
t.RLock()
|
|
defer t.RUnlock()
|
|
return t.tables
|
|
}
|
|
|
|
func (t *sysTablesT) Del(name string) {
|
|
t.Lock()
|
|
defer t.Unlock()
|
|
delete(t.tables, name)
|
|
}
|
|
|
|
var (
|
|
logTag = "nftables:"
|
|
sysTables *sysTablesT
|
|
sysChains *sync.Map
|
|
origSysChains map[string]*nftables.Chain
|
|
sysSets []*nftables.Set
|
|
)
|
|
|
|
// InitMapsStore initializes internal stores of chains and maps.
|
|
func InitMapsStore() {
|
|
sysTables = &sysTablesT{
|
|
tables: make(map[string]*nftables.Table),
|
|
}
|
|
sysChains = &sync.Map{}
|
|
origSysChains = make(map[string]*nftables.Chain)
|
|
}
|
|
|
|
// CreateSystemRule create the custom firewall chains and adds them to system.
|
|
// nft insert rule ip opensnitch-filter opensnitch-input udp dport 1153
|
|
func (n *Nft) CreateSystemRule(chain *config.FwChain, logErrors bool) bool {
|
|
if chain.IsInvalid() {
|
|
log.Warning("%s CreateSystemRule(), Chain's field Name and Family cannot be empty", logTag)
|
|
return false
|
|
}
|
|
|
|
tableName := chain.Table
|
|
n.AddTable(chain.Table, chain.Family)
|
|
|
|
// regular chains doesn't have a hook, nor a type
|
|
if chain.Hook == "" && chain.Type == "" {
|
|
n.addRegularChain(chain.Name, tableName, chain.Family)
|
|
return n.Commit()
|
|
}
|
|
|
|
chainPolicy := nftables.ChainPolicyAccept
|
|
if iptables.Action(strings.ToLower(chain.Policy)) == exprs.VERDICT_DROP {
|
|
chainPolicy = nftables.ChainPolicyDrop
|
|
}
|
|
|
|
chainHook := GetHook(chain.Hook)
|
|
chainPrio, chainType := GetChainPriority(chain.Family, chain.Type, chain.Hook)
|
|
if chainPrio == nil {
|
|
log.Warning("%s Invalid system firewall combination: %s, %s", logTag, chain.Type, chain.Hook)
|
|
return false
|
|
}
|
|
|
|
if ret := n.AddChain(chain.Name, chain.Table, chain.Family, chainPrio,
|
|
chainType, chainHook, chainPolicy); ret == nil {
|
|
log.Warning("%s error adding chain: %s, table: %s", logTag, chain.Name, chain.Table)
|
|
return false
|
|
}
|
|
|
|
return n.Commit()
|
|
}
|
|
|
|
// AddSystemRules creates the system firewall from configuration.
|
|
func (n *Nft) AddSystemRules(reload, backupExistingChains bool) {
|
|
n.SysConfig.RLock()
|
|
defer n.SysConfig.RUnlock()
|
|
|
|
if n.SysConfig.Enabled == false {
|
|
log.Important("[nftables] AddSystemRules() fw disabled")
|
|
return
|
|
}
|
|
if backupExistingChains {
|
|
n.backupExistingChains()
|
|
}
|
|
|
|
for _, fwCfg := range n.SysConfig.SystemRules {
|
|
for _, chain := range fwCfg.Chains {
|
|
if !n.CreateSystemRule(chain, true) {
|
|
log.Info("createSystem failed: %s %s", chain.Name, chain.Table)
|
|
continue
|
|
}
|
|
for i := len(chain.Rules) - 1; i >= 0; i-- {
|
|
if chain.Rules[i].UUID == "" {
|
|
uuid := uuid.New()
|
|
chain.Rules[i].UUID = uuid.String()
|
|
}
|
|
if chain.Rules[i].Enabled {
|
|
if err4, _ := n.AddSystemRule(chain.Rules[i], chain); err4 != nil {
|
|
n.SendError(fmt.Sprintf("%s (%s)", err4, chain.Rules[i].UUID))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeleteSystemRules deletes the system rules.
|
|
// If force is false and the rule has not been previously added,
|
|
// it won't try to delete the tables and chains. Otherwise it'll try to delete them.
|
|
func (n *Nft) DeleteSystemRules(force, restoreExistingChains, logErrors bool) {
|
|
n.Lock()
|
|
defer n.Unlock()
|
|
|
|
if err := n.delRulesByKey(SystemRuleKey); err != nil {
|
|
log.Warning("error deleting interception rules: %s", err)
|
|
}
|
|
|
|
if restoreExistingChains {
|
|
n.restoreBackupChains()
|
|
}
|
|
if force {
|
|
n.DelSystemTables()
|
|
}
|
|
}
|
|
|
|
// AddSystemRule inserts a new rule.
|
|
func (n *Nft) AddSystemRule(rule *config.FwRule, chain *config.FwChain) (err4, err6 error) {
|
|
n.Lock()
|
|
defer n.Unlock()
|
|
exprList := []expr.Any{}
|
|
|
|
for _, expression := range rule.Expressions {
|
|
exprsOfRule := n.parseExpression(chain.Table, chain.Name, chain.Family, expression)
|
|
if exprsOfRule == nil {
|
|
return fmt.Errorf("%s invalid rule parameters: %v", rule.UUID, expression), nil
|
|
}
|
|
exprList = append(exprList, *exprsOfRule...)
|
|
}
|
|
if len(exprList) > 0 {
|
|
exprVerdict := exprs.NewExprVerdict(rule.Target, rule.TargetParameters)
|
|
if exprVerdict == nil {
|
|
return fmt.Errorf("%s invalid verdict %s %s", rule.UUID, rule.Target, rule.TargetParameters), nil
|
|
}
|
|
exprList = append(exprList, *exprVerdict...)
|
|
if err := n.InsertRule(chain.Name, chain.Table, chain.Family, rule.Position, &exprList); err != nil {
|
|
return err, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|