2018-04-02 05:25:32 +02:00
|
|
|
package firewall
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
2020-02-22 00:27:35 +01:00
|
|
|
"time"
|
|
|
|
"regexp"
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2019-10-20 21:51:35 +02:00
|
|
|
"github.com/gustavo-iniguez-goya/opensnitch/daemon/core"
|
2018-04-02 05:25:32 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const DropMark = 0x18BA5
|
|
|
|
|
|
|
|
// make sure we don't mess with multiple rules
|
|
|
|
// at the same time
|
2020-02-22 00:27:35 +01:00
|
|
|
var (
|
|
|
|
lock = sync.Mutex{}
|
|
|
|
|
|
|
|
// check that rules are loaded every 5s
|
|
|
|
rulesChecker = time.NewTicker(time.Second * 5)
|
|
|
|
rulesCheckerChan = make(chan bool)
|
|
|
|
regexRulesQuery, _ = regexp.Compile(`NFQUEUE.*ctstate NEW.*NFQUEUE num.*bypass`)
|
|
|
|
regexDropQuery, _ = regexp.Compile(`DROP.*mark match 0x18ba5`)
|
|
|
|
)
|
2018-04-02 05:25:32 +02:00
|
|
|
|
|
|
|
func RunRule(enable bool, rule []string) (err error) {
|
|
|
|
action := "-A"
|
|
|
|
if enable == false {
|
|
|
|
action = "-D"
|
|
|
|
}
|
|
|
|
|
|
|
|
rule = append([]string{action}, rule...)
|
|
|
|
|
|
|
|
lock.Lock()
|
|
|
|
defer lock.Unlock()
|
|
|
|
|
|
|
|
// fmt.Printf("iptables %s\n", rule)
|
|
|
|
|
|
|
|
_, err = core.Exec("iptables", rule)
|
2018-12-30 19:07:05 -08:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-11-21 00:25:47 +01:00
|
|
|
_, err = core.Exec("ip6tables", rule)
|
2019-01-26 20:56:12 -08:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-11-21 00:25:47 +01:00
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// INPUT --protocol udp --sport 53 -j NFQUEUE --queue-num 0 --queue-bypass
|
|
|
|
func QueueDNSResponses(enable bool, queueNum int) (err error) {
|
2018-08-23 22:44:48 -07:00
|
|
|
// If enable, we're going to insert as #1, not append
|
|
|
|
if enable {
|
|
|
|
// FIXME: this is basically copy/paste of RunRule() above b/c we can't
|
|
|
|
// shoehorn "-I" with the boolean 'enable' switch
|
|
|
|
rule := []string{
|
|
|
|
"-I",
|
|
|
|
"INPUT",
|
|
|
|
"1",
|
|
|
|
"--protocol", "udp",
|
|
|
|
"--sport", "53",
|
|
|
|
"-j", "NFQUEUE",
|
|
|
|
"--queue-num", fmt.Sprintf("%d", queueNum),
|
|
|
|
"--queue-bypass",
|
|
|
|
}
|
2019-01-26 20:56:12 -08:00
|
|
|
|
2018-08-23 22:44:48 -07:00
|
|
|
lock.Lock()
|
|
|
|
defer lock.Unlock()
|
2019-01-26 20:56:12 -08:00
|
|
|
|
2018-08-23 22:44:48 -07:00
|
|
|
_, err := core.Exec("iptables", rule)
|
2019-01-26 20:56:12 -08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = core.Exec("ip6tables", rule)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-08-23 22:44:48 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, it's going to be disable
|
2018-04-02 05:25:32 +02:00
|
|
|
return RunRule(enable, []string{
|
|
|
|
"INPUT",
|
|
|
|
"--protocol", "udp",
|
|
|
|
"--sport", "53",
|
|
|
|
"-j", "NFQUEUE",
|
|
|
|
"--queue-num", fmt.Sprintf("%d", queueNum),
|
|
|
|
"--queue-bypass",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// OUTPUT -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass
|
|
|
|
func QueueConnections(enable bool, queueNum int) (err error) {
|
2020-02-22 00:27:35 +01:00
|
|
|
regexRulesQuery, _ = regexp.Compile(fmt.Sprint(`NFQUEUE.*ctstate NEW.*NFQUEUE num `, queueNum, ` bypass`))
|
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
return RunRule(enable, []string{
|
|
|
|
"OUTPUT",
|
|
|
|
"-t", "mangle",
|
|
|
|
"-m", "conntrack",
|
|
|
|
"--ctstate", "NEW",
|
|
|
|
"-j", "NFQUEUE",
|
|
|
|
"--queue-num", fmt.Sprintf("%d", queueNum),
|
|
|
|
"--queue-bypass",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reject packets marked by OpenSnitch
|
2018-04-10 13:11:39 +02:00
|
|
|
// OUTPUT -m mark --mark 101285 -j DROP
|
|
|
|
func DropMarked(enable bool) (err error) {
|
2018-04-02 05:25:32 +02:00
|
|
|
return RunRule(enable, []string{
|
|
|
|
"OUTPUT",
|
|
|
|
"-m", "mark",
|
|
|
|
"--mark", fmt.Sprintf("%d", DropMark),
|
2018-04-10 13:11:39 +02:00
|
|
|
"-j", "DROP",
|
2018-04-02 05:25:32 +02:00
|
|
|
})
|
|
|
|
}
|
2020-02-22 00:27:35 +01:00
|
|
|
|
|
|
|
func AreRulesLoaded() bool {
|
|
|
|
lock.Lock()
|
|
|
|
defer lock.Unlock()
|
|
|
|
|
|
|
|
outDrop, err := core.Exec("iptables", []string{"-L", "OUTPUT"})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
outDrop6, err := core.Exec("ip6tables", []string{"-L", "OUTPUT"})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
outMangle, err := core.Exec("iptables", []string{"-L", "OUTPUT", "-t", "mangle"})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
outMangle6, err := core.Exec("ip6tables", []string{"-L", "OUTPUT", "-t", "mangle"})
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return regexRulesQuery.FindString(outMangle) != "" &&
|
|
|
|
regexRulesQuery.FindString(outMangle6) != "" &&
|
|
|
|
regexDropQuery.FindString(outDrop) != "" &&
|
|
|
|
regexDropQuery.FindString(outDrop6) != ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func StartCheckingRules(qNum int) {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-rulesCheckerChan:
|
|
|
|
fmt.Println("Stop checking rules")
|
|
|
|
return
|
|
|
|
case <-rulesChecker.C:
|
|
|
|
rules := AreRulesLoaded()
|
|
|
|
if rules == false {
|
|
|
|
QueueConnections(false, qNum)
|
|
|
|
DropMarked(false)
|
|
|
|
QueueConnections(true, qNum)
|
|
|
|
DropMarked(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func StopCheckingRules() {
|
|
|
|
rulesCheckerChan <- true
|
|
|
|
}
|