opensnitch/daemon/firewall/rules.go
Gustavo Iñiguez Goia 6622df9d38
allow to configure nfqueue bypass flag
Nfqueue bypass option skips the enqueue of packets to userspace
if no application is listening to the queue.
https://wiki.nftables.org/wiki-nftables/index.php/Queueing_to_userspace

If this flag is not specified, and for example the daemon dies
unexpectedly, all the outbound traffic will be blocked.

Up until now we've been using this flag by default not to block network
traffic if the daemon dies or is killed for some reason. But some users
want to use precisely this behaviour (#884, #1183, #1201).

Now you can configure it, to block connections if the daemon
unexpectedly dies.

The option is on by default in the configuration (QueueBypass: true).
If this item is not present in the daemon config file, then it'll be
false.
2024-10-19 10:51:40 +02:00

158 lines
4.1 KiB
Go

package firewall
import (
"fmt"
"github.com/evilsocket/opensnitch/daemon/firewall/common"
"github.com/evilsocket/opensnitch/daemon/firewall/config"
"github.com/evilsocket/opensnitch/daemon/firewall/iptables"
"github.com/evilsocket/opensnitch/daemon/firewall/nftables"
"github.com/evilsocket/opensnitch/daemon/log"
"github.com/evilsocket/opensnitch/daemon/ui/protocol"
)
// Firewall is the interface that all firewalls (iptables, nftables) must implement.
type Firewall interface {
Init(uint16, string, string, bool)
Stop()
Name() string
IsRunning() bool
SetQueueNum(num uint16)
SaveConfiguration(rawConfig string) error
EnableInterception()
DisableInterception(bool)
QueueDNSResponses(bool, bool) (error, error)
QueueConnections(bool, bool) (error, error)
CleanRules(bool)
AddSystemRules(bool, bool)
DeleteSystemRules(bool, bool, bool)
Serialize() (*protocol.SysFirewall, error)
Deserialize(sysfw *protocol.SysFirewall) ([]byte, error)
ErrorsChan() <-chan string
ErrChanEmpty() bool
}
var (
fw Firewall
queueNum = uint16(0)
)
// Init initializes the firewall and loads firewall rules.
// 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, bypassQueue bool, qNum uint16) (err error) {
if fwType == iptables.Name {
fw, err = iptables.Fw()
if err != nil {
log.Warning("iptables not available: %s", err)
}
}
if fwType == nftables.Name || err != nil {
fw, err = nftables.Fw()
if err != nil {
log.Warning("nftables not available: %s", err)
}
}
if err != nil {
return fmt.Errorf("firewall error: %s, not iptables nor nftables are available or are usable. Please, report it on github", err)
}
if fw == nil {
return fmt.Errorf("Firewall not initialized")
}
if configPath == "" {
configPath = config.DefaultConfigFile
}
fw.Stop()
fw.Init(qNum, configPath, monitorInterval, bypassQueue)
queueNum = qNum
log.Info("Using %s firewall", fw.Name())
return
}
// IsRunning returns if the firewall is running or not.
func IsRunning() bool {
return fw != nil && fw.IsRunning()
}
// ErrorsChan returns the channel where the errors are sent to.
func ErrorsChan() <-chan string {
return fw.ErrorsChan()
}
// ErrChanEmpty checks if the errors channel is empty.
func ErrChanEmpty() bool {
return fw.ErrChanEmpty()
}
// CleanRules deletes the rules we added.
func CleanRules(logErrors bool) {
if fw == nil {
return
}
fw.CleanRules(logErrors)
}
// Reload stops current firewall and initializes a new one.
func Reload(fwtype, configPath, monitorInterval string, bypassQueue bool, queueNum uint16) (err error) {
Stop()
err = Init(fwtype, configPath, monitorInterval, bypassQueue, queueNum)
return
}
// ReloadSystemRules deletes existing rules, and add them again
func ReloadSystemRules() {
fw.DeleteSystemRules(!common.ForcedDelRules, common.RestoreChains, true)
fw.AddSystemRules(common.ReloadRules, common.BackupChains)
}
// EnableInterception removes the rules to intercept outbound connections.
func EnableInterception() error {
if fw == nil {
return fmt.Errorf("firewall not initialized when trying to enable interception, report please")
}
fw.EnableInterception()
return nil
}
// DisableInterception removes the rules to intercept outbound connections.
func DisableInterception() error {
if fw == nil {
return fmt.Errorf("firewall not initialized when trying to disable interception, report please")
}
fw.DisableInterception(true)
return nil
}
// Stop deletes the firewall rules, allowing network traffic.
func Stop() {
if fw == nil {
return
}
fw.Stop()
}
// SaveConfiguration saves configuration string to disk
func SaveConfiguration(rawConfig []byte) error {
return fw.SaveConfiguration(string(rawConfig))
}
// Serialize transforms firewall json configuration to protobuf
func Serialize() (*protocol.SysFirewall, error) {
return fw.Serialize()
}
// Deserialize transforms firewall json configuration to protobuf
func Deserialize(sysfw *protocol.SysFirewall) ([]byte, error) {
return fw.Deserialize(sysfw)
}