mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-17 12:20:51 +01:00
e69ec6ab6a
* Optimize rules with All groups * Use IP sets in ACLs (nftables implementation) * Fix squash rule when we receive optimized rules list from management
116 lines
2.6 KiB
Go
116 lines
2.6 KiB
Go
package nftables
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"github.com/google/nftables"
|
|
"github.com/rs/xid"
|
|
)
|
|
|
|
// nftRuleset links native firewall rule and ipset to ACL generated rules
|
|
type nftRuleset struct {
|
|
nftRule *nftables.Rule
|
|
nftSet *nftables.Set
|
|
issuedRules map[string]*Rule
|
|
rulesetID string
|
|
}
|
|
|
|
type rulesetManager struct {
|
|
rulesets map[string]*nftRuleset
|
|
|
|
nftSetName2rulesetID map[string]string
|
|
issuedRuleID2rulesetID map[string]string
|
|
}
|
|
|
|
func newRuleManager() *rulesetManager {
|
|
return &rulesetManager{
|
|
rulesets: map[string]*nftRuleset{},
|
|
|
|
nftSetName2rulesetID: map[string]string{},
|
|
issuedRuleID2rulesetID: map[string]string{},
|
|
}
|
|
}
|
|
|
|
func (r *rulesetManager) getRuleset(rulesetID string) (*nftRuleset, bool) {
|
|
ruleset, ok := r.rulesets[rulesetID]
|
|
return ruleset, ok
|
|
}
|
|
|
|
func (r *rulesetManager) createRuleset(
|
|
rulesetID string,
|
|
nftRule *nftables.Rule,
|
|
nftSet *nftables.Set,
|
|
) *nftRuleset {
|
|
ruleset := nftRuleset{
|
|
rulesetID: rulesetID,
|
|
nftRule: nftRule,
|
|
nftSet: nftSet,
|
|
issuedRules: map[string]*Rule{},
|
|
}
|
|
r.rulesets[ruleset.rulesetID] = &ruleset
|
|
if nftSet != nil {
|
|
r.nftSetName2rulesetID[nftSet.Name] = ruleset.rulesetID
|
|
}
|
|
return &ruleset
|
|
}
|
|
|
|
func (r *rulesetManager) addRule(
|
|
ruleset *nftRuleset,
|
|
ip []byte,
|
|
) (*Rule, error) {
|
|
if _, ok := r.rulesets[ruleset.rulesetID]; !ok {
|
|
return nil, fmt.Errorf("ruleset not found")
|
|
}
|
|
|
|
rule := Rule{
|
|
nftRule: ruleset.nftRule,
|
|
nftSet: ruleset.nftSet,
|
|
ruleID: xid.New().String(),
|
|
ip: ip,
|
|
}
|
|
|
|
ruleset.issuedRules[rule.ruleID] = &rule
|
|
r.issuedRuleID2rulesetID[rule.ruleID] = ruleset.rulesetID
|
|
|
|
return &rule, nil
|
|
}
|
|
|
|
// deleteRule from ruleset and returns true if contains other rules
|
|
func (r *rulesetManager) deleteRule(rule *Rule) bool {
|
|
rulesetID, ok := r.issuedRuleID2rulesetID[rule.ruleID]
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
ruleset := r.rulesets[rulesetID]
|
|
if ruleset.nftRule == nil {
|
|
return false
|
|
}
|
|
delete(r.issuedRuleID2rulesetID, rule.ruleID)
|
|
delete(ruleset.issuedRules, rule.ruleID)
|
|
|
|
if len(ruleset.issuedRules) == 0 {
|
|
delete(r.rulesets, ruleset.rulesetID)
|
|
if rule.nftSet != nil {
|
|
delete(r.nftSetName2rulesetID, rule.nftSet.Name)
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// setNftRuleHandle finds rule by userdata which contains rulesetID and updates it's handle number
|
|
//
|
|
// This is important to do, because after we add rule to the nftables we can't update it until
|
|
// we set correct handle value to it.
|
|
func (r *rulesetManager) setNftRuleHandle(nftRule *nftables.Rule) error {
|
|
split := bytes.Split(nftRule.UserData, []byte(" "))
|
|
ruleset, ok := r.rulesets[string(split[0])]
|
|
if !ok {
|
|
return fmt.Errorf("ruleset not found")
|
|
}
|
|
*ruleset.nftRule = *nftRule
|
|
return nil
|
|
}
|