diff --git a/daemon/default-config.json b/daemon/default-config.json index c79cea6b54..143ee9cf09 100644 --- a/daemon/default-config.json +++ b/daemon/default-config.json @@ -17,7 +17,8 @@ "Firewall": "nftables", "FwOptions": { "ConfigPath": "/etc/opensnitchd/system-fw.json", - "MonitorInterval": "15s" + "MonitorInterval": "15s", + "BypassQueue": true }, "Rules": { "Path": "/etc/opensnitchd/rules/", diff --git a/daemon/firewall/iptables/iptables.go b/daemon/firewall/iptables/iptables.go index 5e64ab59bf..7e4a827902 100644 --- a/daemon/firewall/iptables/iptables.go +++ b/daemon/firewall/iptables/iptables.go @@ -59,6 +59,7 @@ type Iptables struct { bin string bin6 string chains SystemChains + bypassQueue bool common.Common config.Config @@ -71,7 +72,7 @@ func Fw() (*Iptables, error) { return nil, err } - reRulesQuery, _ := regexp.Compile(`NFQUEUE.*ctstate NEW,RELATED.*NFQUEUE num.*bypass`) + reRulesQuery, _ := regexp.Compile(`NFQUEUE.*ctstate NEW,RELATED.*NFQUEUE num.*`) reSystemRulesQuery, _ := regexp.Compile(SystemRulePrefix + ".*") ipt := &Iptables{ @@ -93,10 +94,11 @@ func (ipt *Iptables) Name() string { // Init inserts the firewall rules and starts monitoring for firewall // changes. -func (ipt *Iptables) Init(qNum uint16, configPath, monitorInterval string) { +func (ipt *Iptables) Init(qNum uint16, configPath, monitorInterval string, bypassQueue bool) { if ipt.IsRunning() { return } + ipt.bypassQueue = bypassQueue ipt.SetQueueNum(qNum) ipt.SetRulesCheckerInterval(monitorInterval) ipt.ErrChan = make(chan string, 100) diff --git a/daemon/firewall/iptables/rules.go b/daemon/firewall/iptables/rules.go index 6eed8422ca..2cc77d2188 100644 --- a/daemon/firewall/iptables/rules.go +++ b/daemon/firewall/iptables/rules.go @@ -8,12 +8,27 @@ import ( "github.com/vishvananda/netlink" ) +func (ipt *Iptables) getBypassQueue() string { + if !ipt.bypassQueue { + return "" + } + + return "--queue-bypass" +} + // RunRule inserts or deletes a firewall rule. func (ipt *Iptables) RunRule(action Action, enable bool, logError bool, rule []string) (err4, err6 error) { if enable == false { action = "-D" } + // If the last argument of the rule is "", the iptables command fails. + // So if the user selects "QueueBypass: false", delete the last token of the rule, + // which will be "". + args := len(rule) + if rule[args-1] == "" { + rule = append(rule[:args-1], rule[args:]...) + } rule = append([]string{string(action)}, rule...) ipt.Lock() @@ -49,7 +64,7 @@ func (ipt *Iptables) QueueDNSResponses(enable bool, logError bool) (err4, err6 e "--sport", "53", "-j", "NFQUEUE", "--queue-num", fmt.Sprintf("%d", ipt.QueueNum), - "--queue-bypass", + ipt.getBypassQueue(), }) } @@ -64,7 +79,7 @@ func (ipt *Iptables) QueueConnections(enable bool, logError bool) (error, error) "--ctstate", "NEW,RELATED", "-j", "NFQUEUE", "--queue-num", fmt.Sprintf("%d", ipt.QueueNum), - "--queue-bypass", + ipt.getBypassQueue(), }) if enable { // flush conntrack as soon as netfilter rule is set. This ensures that already-established diff --git a/daemon/firewall/nftables/nftables.go b/daemon/firewall/nftables/nftables.go index c0277b18f1..cd9316fe95 100644 --- a/daemon/firewall/nftables/nftables.go +++ b/daemon/firewall/nftables/nftables.go @@ -41,8 +41,9 @@ var ( // Nft holds the fields of our nftables firewall type Nft struct { - Conn *nftables.Conn - chains iptables.SystemChains + Conn *nftables.Conn + chains iptables.SystemChains + bypassQueue bool common.Common config.Config @@ -71,10 +72,11 @@ func (n *Nft) Name() string { // Init inserts the firewall rules and starts monitoring for firewall // changes. -func (n *Nft) Init(qNum uint16, configPath, monitorInterval string) { +func (n *Nft) Init(qNum uint16, configPath, monitorInterval string, bypassQueue bool) { if n.IsRunning() { return } + n.bypassQueue = bypassQueue n.Conn = NewNft() n.ErrChan = make(chan string, 100) InitMapsStore() diff --git a/daemon/firewall/nftables/rules.go b/daemon/firewall/nftables/rules.go index 1595a7d91f..791366ee66 100644 --- a/daemon/firewall/nftables/rules.go +++ b/daemon/firewall/nftables/rules.go @@ -57,7 +57,7 @@ func (n *Nft) QueueDNSResponses(enable, logError bool) (error, error) { }, &expr.Queue{ Num: n.QueueNum, - Flag: expr.QueueFlagBypass, + Flag: n.getBypassFlag(), }, }, // rule key, to allow get it later by key @@ -112,7 +112,7 @@ func (n *Nft) QueueConnections(enable, logError bool) (error, error) { &expr.Cmp{Op: expr.CmpOpNeq, Register: 1, Data: []byte{0, 0, 0, 0}}, &expr.Queue{ Num: n.QueueNum, - Flag: expr.QueueFlagBypass, + Flag: n.getBypassFlag(), }, }, // rule key, to allow get it later by key @@ -163,7 +163,7 @@ func (n *Nft) QueueConnections(enable, logError bool) (error, error) { }, &expr.Queue{ Num: n.QueueNum, - Flag: expr.QueueFlagBypass, + Flag: n.getBypassFlag(), }, }, // rule key, to allow get it later by key diff --git a/daemon/firewall/nftables/utils.go b/daemon/firewall/nftables/utils.go index dbb3d19efc..50ad50cf52 100644 --- a/daemon/firewall/nftables/utils.go +++ b/daemon/firewall/nftables/utils.go @@ -6,8 +6,17 @@ import ( "github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs" "github.com/evilsocket/opensnitch/daemon/log" "github.com/google/nftables" + "github.com/google/nftables/expr" ) +func (n *Nft) getBypassFlag() expr.QueueFlag { + if n.bypassQueue { + return expr.QueueFlagBypass + } + + return 0x0 +} + func GetFamilyCode(family string) nftables.TableFamily { famCode := nftables.TableFamilyINet switch family { diff --git a/daemon/firewall/rules.go b/daemon/firewall/rules.go index 6eaacf2277..80dc222eb9 100644 --- a/daemon/firewall/rules.go +++ b/daemon/firewall/rules.go @@ -13,7 +13,7 @@ import ( // Firewall is the interface that all firewalls (iptables, nftables) must implement. type Firewall interface { - Init(uint16, string, string) + Init(uint16, string, string, bool) Stop() Name() string IsRunning() bool @@ -46,7 +46,7 @@ var ( // We'll try to use the firewall configured in the configuration (iptables/nftables). // If iptables is not installed, we can add nftables rules directly to the kernel, // without relying on any binaries. -func Init(fwType, configPath, monitorInterval string, qNum uint16) (err error) { +func Init(fwType, configPath, monitorInterval string, bypassQueue bool, qNum uint16) (err error) { if fwType == iptables.Name { fw, err = iptables.Fw() if err != nil { @@ -72,7 +72,7 @@ func Init(fwType, configPath, monitorInterval string, qNum uint16) (err error) { configPath = config.DefaultConfigFile } fw.Stop() - fw.Init(qNum, configPath, monitorInterval) + fw.Init(qNum, configPath, monitorInterval, bypassQueue) queueNum = qNum log.Info("Using %s firewall", fw.Name()) @@ -104,9 +104,9 @@ func CleanRules(logErrors bool) { } // Reload stops current firewall and initializes a new one. -func Reload(fwtype, configPath, monitorInterval string, queueNum uint16) (err error) { +func Reload(fwtype, configPath, monitorInterval string, bypassQueue bool, queueNum uint16) (err error) { Stop() - err = Init(fwtype, configPath, monitorInterval, queueNum) + err = Init(fwtype, configPath, monitorInterval, bypassQueue, queueNum) return } diff --git a/daemon/main.go b/daemon/main.go index f4fd449ce0..2b29676ece 100644 --- a/daemon/main.go +++ b/daemon/main.go @@ -157,6 +157,7 @@ func overwriteFw(cfg *config.Config, qNum uint16, fwCfg string) { cfg.Firewall, fwCfg, cfg.FwOptions.MonitorInterval, + cfg.FwOptions.QueueBypass, qNum, ) // TODO: Close() closes the daemon if closing the queue timeouts diff --git a/daemon/ui/config/config.go b/daemon/ui/config/config.go index 673132b75d..adce9ce065 100644 --- a/daemon/ui/config/config.go +++ b/daemon/ui/config/config.go @@ -57,9 +57,9 @@ type ( FwOptions struct { Firewall string `json:"Firewall"` ConfigPath string `json:"ConfigPath"` - BypassQueue string `json:"BypassQueue"` MonitorInterval string `json:"MonitorInterval"` QueueNum uint16 `json:"QueueNum"` + QueueBypass bool `json:"QueueBypass"` } // InternalOptions struct diff --git a/daemon/ui/config_utils.go b/daemon/ui/config_utils.go index 81ea569f53..d59bc6c85f 100644 --- a/daemon/ui/config_utils.go +++ b/daemon/ui/config_utils.go @@ -204,7 +204,8 @@ func (c *Client) reloadConfiguration(reload bool, newConfig config.Config) *moni if c.GetFirewallType() != newConfig.Firewall || newConfig.FwOptions.ConfigPath != c.config.FwOptions.ConfigPath || newConfig.FwOptions.QueueNum != c.config.FwOptions.QueueNum || - newConfig.FwOptions.MonitorInterval != c.config.FwOptions.MonitorInterval { + newConfig.FwOptions.MonitorInterval != c.config.FwOptions.MonitorInterval || + newConfig.FwOptions.QueueBypass != c.config.FwOptions.QueueBypass { log.Debug("[config] reloading config.firewall") reloadFw = true @@ -212,6 +213,7 @@ func (c *Client) reloadConfiguration(reload bool, newConfig config.Config) *moni newConfig.Firewall, newConfig.FwOptions.ConfigPath, newConfig.FwOptions.MonitorInterval, + newConfig.FwOptions.QueueBypass, newConfig.FwOptions.QueueNum, ) } else {