Skip to content

Commit 6622df9

Browse files
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.
1 parent ebac200 commit 6622df9

File tree

10 files changed

+50
-18
lines changed

10 files changed

+50
-18
lines changed

daemon/default-config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"Firewall": "nftables",
1818
"FwOptions": {
1919
"ConfigPath": "/etc/opensnitchd/system-fw.json",
20-
"MonitorInterval": "15s"
20+
"MonitorInterval": "15s",
21+
"BypassQueue": true
2122
},
2223
"Rules": {
2324
"Path": "/etc/opensnitchd/rules/",

daemon/firewall/iptables/iptables.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Iptables struct {
5959
bin string
6060
bin6 string
6161
chains SystemChains
62+
bypassQueue bool
6263
common.Common
6364
config.Config
6465

@@ -71,7 +72,7 @@ func Fw() (*Iptables, error) {
7172
return nil, err
7273
}
7374

74-
reRulesQuery, _ := regexp.Compile(`NFQUEUE.*ctstate NEW,RELATED.*NFQUEUE num.*bypass`)
75+
reRulesQuery, _ := regexp.Compile(`NFQUEUE.*ctstate NEW,RELATED.*NFQUEUE num.*`)
7576
reSystemRulesQuery, _ := regexp.Compile(SystemRulePrefix + ".*")
7677

7778
ipt := &Iptables{
@@ -93,10 +94,11 @@ func (ipt *Iptables) Name() string {
9394

9495
// Init inserts the firewall rules and starts monitoring for firewall
9596
// changes.
96-
func (ipt *Iptables) Init(qNum uint16, configPath, monitorInterval string) {
97+
func (ipt *Iptables) Init(qNum uint16, configPath, monitorInterval string, bypassQueue bool) {
9798
if ipt.IsRunning() {
9899
return
99100
}
101+
ipt.bypassQueue = bypassQueue
100102
ipt.SetQueueNum(qNum)
101103
ipt.SetRulesCheckerInterval(monitorInterval)
102104
ipt.ErrChan = make(chan string, 100)

daemon/firewall/iptables/rules.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,27 @@ import (
88
"github.com/vishvananda/netlink"
99
)
1010

11+
func (ipt *Iptables) getBypassQueue() string {
12+
if !ipt.bypassQueue {
13+
return ""
14+
}
15+
16+
return "--queue-bypass"
17+
}
18+
1119
// RunRule inserts or deletes a firewall rule.
1220
func (ipt *Iptables) RunRule(action Action, enable bool, logError bool, rule []string) (err4, err6 error) {
1321
if enable == false {
1422
action = "-D"
1523
}
1624

25+
// If the last argument of the rule is "", the iptables command fails.
26+
// So if the user selects "QueueBypass: false", delete the last token of the rule,
27+
// which will be "".
28+
args := len(rule)
29+
if rule[args-1] == "" {
30+
rule = append(rule[:args-1], rule[args:]...)
31+
}
1732
rule = append([]string{string(action)}, rule...)
1833

1934
ipt.Lock()
@@ -49,7 +64,7 @@ func (ipt *Iptables) QueueDNSResponses(enable bool, logError bool) (err4, err6 e
4964
"--sport", "53",
5065
"-j", "NFQUEUE",
5166
"--queue-num", fmt.Sprintf("%d", ipt.QueueNum),
52-
"--queue-bypass",
67+
ipt.getBypassQueue(),
5368
})
5469
}
5570

@@ -64,7 +79,7 @@ func (ipt *Iptables) QueueConnections(enable bool, logError bool) (error, error)
6479
"--ctstate", "NEW,RELATED",
6580
"-j", "NFQUEUE",
6681
"--queue-num", fmt.Sprintf("%d", ipt.QueueNum),
67-
"--queue-bypass",
82+
ipt.getBypassQueue(),
6883
})
6984
if enable {
7085
// flush conntrack as soon as netfilter rule is set. This ensures that already-established

daemon/firewall/nftables/nftables.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ var (
4141

4242
// Nft holds the fields of our nftables firewall
4343
type Nft struct {
44-
Conn *nftables.Conn
45-
chains iptables.SystemChains
44+
Conn *nftables.Conn
45+
chains iptables.SystemChains
46+
bypassQueue bool
4647

4748
common.Common
4849
config.Config
@@ -71,10 +72,11 @@ func (n *Nft) Name() string {
7172

7273
// Init inserts the firewall rules and starts monitoring for firewall
7374
// changes.
74-
func (n *Nft) Init(qNum uint16, configPath, monitorInterval string) {
75+
func (n *Nft) Init(qNum uint16, configPath, monitorInterval string, bypassQueue bool) {
7576
if n.IsRunning() {
7677
return
7778
}
79+
n.bypassQueue = bypassQueue
7880
n.Conn = NewNft()
7981
n.ErrChan = make(chan string, 100)
8082
InitMapsStore()

daemon/firewall/nftables/rules.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (n *Nft) QueueDNSResponses(enable, logError bool) (error, error) {
5757
},
5858
&expr.Queue{
5959
Num: n.QueueNum,
60-
Flag: expr.QueueFlagBypass,
60+
Flag: n.getBypassFlag(),
6161
},
6262
},
6363
// rule key, to allow get it later by key
@@ -112,7 +112,7 @@ func (n *Nft) QueueConnections(enable, logError bool) (error, error) {
112112
&expr.Cmp{Op: expr.CmpOpNeq, Register: 1, Data: []byte{0, 0, 0, 0}},
113113
&expr.Queue{
114114
Num: n.QueueNum,
115-
Flag: expr.QueueFlagBypass,
115+
Flag: n.getBypassFlag(),
116116
},
117117
},
118118
// rule key, to allow get it later by key
@@ -163,7 +163,7 @@ func (n *Nft) QueueConnections(enable, logError bool) (error, error) {
163163
},
164164
&expr.Queue{
165165
Num: n.QueueNum,
166-
Flag: expr.QueueFlagBypass,
166+
Flag: n.getBypassFlag(),
167167
},
168168
},
169169
// rule key, to allow get it later by key

daemon/firewall/nftables/utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@ import (
66
"github.com/evilsocket/opensnitch/daemon/firewall/nftables/exprs"
77
"github.com/evilsocket/opensnitch/daemon/log"
88
"github.com/google/nftables"
9+
"github.com/google/nftables/expr"
910
)
1011

12+
func (n *Nft) getBypassFlag() expr.QueueFlag {
13+
if n.bypassQueue {
14+
return expr.QueueFlagBypass
15+
}
16+
17+
return 0x0
18+
}
19+
1120
func GetFamilyCode(family string) nftables.TableFamily {
1221
famCode := nftables.TableFamilyINet
1322
switch family {

daemon/firewall/rules.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313

1414
// Firewall is the interface that all firewalls (iptables, nftables) must implement.
1515
type Firewall interface {
16-
Init(uint16, string, string)
16+
Init(uint16, string, string, bool)
1717
Stop()
1818
Name() string
1919
IsRunning() bool
@@ -46,7 +46,7 @@ var (
4646
// We'll try to use the firewall configured in the configuration (iptables/nftables).
4747
// If iptables is not installed, we can add nftables rules directly to the kernel,
4848
// without relying on any binaries.
49-
func Init(fwType, configPath, monitorInterval string, qNum uint16) (err error) {
49+
func Init(fwType, configPath, monitorInterval string, bypassQueue bool, qNum uint16) (err error) {
5050
if fwType == iptables.Name {
5151
fw, err = iptables.Fw()
5252
if err != nil {
@@ -72,7 +72,7 @@ func Init(fwType, configPath, monitorInterval string, qNum uint16) (err error) {
7272
configPath = config.DefaultConfigFile
7373
}
7474
fw.Stop()
75-
fw.Init(qNum, configPath, monitorInterval)
75+
fw.Init(qNum, configPath, monitorInterval, bypassQueue)
7676
queueNum = qNum
7777

7878
log.Info("Using %s firewall", fw.Name())
@@ -104,9 +104,9 @@ func CleanRules(logErrors bool) {
104104
}
105105

106106
// Reload stops current firewall and initializes a new one.
107-
func Reload(fwtype, configPath, monitorInterval string, queueNum uint16) (err error) {
107+
func Reload(fwtype, configPath, monitorInterval string, bypassQueue bool, queueNum uint16) (err error) {
108108
Stop()
109-
err = Init(fwtype, configPath, monitorInterval, queueNum)
109+
err = Init(fwtype, configPath, monitorInterval, bypassQueue, queueNum)
110110
return
111111
}
112112

daemon/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ func overwriteFw(cfg *config.Config, qNum uint16, fwCfg string) {
157157
cfg.Firewall,
158158
fwCfg,
159159
cfg.FwOptions.MonitorInterval,
160+
cfg.FwOptions.QueueBypass,
160161
qNum,
161162
)
162163
// TODO: Close() closes the daemon if closing the queue timeouts

daemon/ui/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ type (
5757
FwOptions struct {
5858
Firewall string `json:"Firewall"`
5959
ConfigPath string `json:"ConfigPath"`
60-
BypassQueue string `json:"BypassQueue"`
6160
MonitorInterval string `json:"MonitorInterval"`
6261
QueueNum uint16 `json:"QueueNum"`
62+
QueueBypass bool `json:"QueueBypass"`
6363
}
6464

6565
// InternalOptions struct

daemon/ui/config_utils.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,16 @@ func (c *Client) reloadConfiguration(reload bool, newConfig config.Config) *moni
204204
if c.GetFirewallType() != newConfig.Firewall ||
205205
newConfig.FwOptions.ConfigPath != c.config.FwOptions.ConfigPath ||
206206
newConfig.FwOptions.QueueNum != c.config.FwOptions.QueueNum ||
207-
newConfig.FwOptions.MonitorInterval != c.config.FwOptions.MonitorInterval {
207+
newConfig.FwOptions.MonitorInterval != c.config.FwOptions.MonitorInterval ||
208+
newConfig.FwOptions.QueueBypass != c.config.FwOptions.QueueBypass {
208209
log.Debug("[config] reloading config.firewall")
209210
reloadFw = true
210211

211212
firewall.Reload(
212213
newConfig.Firewall,
213214
newConfig.FwOptions.ConfigPath,
214215
newConfig.FwOptions.MonitorInterval,
216+
newConfig.FwOptions.QueueBypass,
215217
newConfig.FwOptions.QueueNum,
216218
)
217219
} else {

0 commit comments

Comments
 (0)