You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fw-daemon/sgfw/sgfw.go

208 lines
3.6 KiB

package sgfw
9 years ago
import (
"os"
"os/signal"
"sync"
"syscall"
"time"
9 years ago
"github.com/op/go-logging"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
// "github.com/subgraph/go-nfnetlink"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/subgraph/fw-daemon/proc-coroner"
"github.com/subgraph/go-procsnitch"
9 years ago
)
var dbLogger *dbusObjectP = nil
9 years ago
type Firewall struct {
dbus *dbusServer
dns *dnsCache
enabled bool
logBackend logging.LeveledBackend
9 years ago
lock sync.Mutex
policyMap map[string]*Policy
policies []*Policy
ruleLock sync.Mutex
8 years ago
rulesByID map[uint]*Rule
nextRuleID uint
reloadRulesChan chan bool
stopChan chan bool
}
func (fw *Firewall) setEnabled(flag bool) {
fw.lock.Lock()
defer fw.lock.Unlock()
fw.enabled = flag
}
func (fw *Firewall) isEnabled() bool {
fw.lock.Lock()
defer fw.lock.Unlock()
return fw.enabled
}
func (fw *Firewall) clearRules() {
fw.ruleLock.Lock()
defer fw.ruleLock.Unlock()
8 years ago
fw.rulesByID = nil
fw.nextRuleID = 0
}
func (fw *Firewall) addRule(r *Rule) {
fw.ruleLock.Lock()
defer fw.ruleLock.Unlock()
8 years ago
r.id = fw.nextRuleID
fw.nextRuleID++
if fw.rulesByID == nil {
fw.rulesByID = make(map[uint]*Rule)
}
8 years ago
fw.rulesByID[r.id] = r
}
8 years ago
func (fw *Firewall) getRuleByID(id uint) *Rule {
fw.ruleLock.Lock()
defer fw.ruleLock.Unlock()
8 years ago
if fw.rulesByID == nil {
return nil
}
8 years ago
return fw.rulesByID[id]
9 years ago
}
func (fw *Firewall) stop() {
fw.stopChan <- true
}
func (fw *Firewall) reloadRules() {
fw.reloadRulesChan <- true
}
9 years ago
func (fw *Firewall) runFilter() {
q := nfqueue.NewNFQueue(0)
// XXX: need to implement this
// q.DefaultVerdict = nfqueue.DROP
// XXX: need this as well
// q.Timeout = 5 * time.Minute
9 years ago
ps, err := q.Open()
if err != nil {
log.Fatal("Error opening NFQueue:", err)
}
q.EnableHWTrace()
defer q.Close()
go func() {
for p := range ps {
timestamp := time.Now()
if fw.isEnabled() {
ipLayer := p.Packet.Layer(layers.LayerTypeIPv4)
if ipLayer == nil {
continue
}
ip, _ := ipLayer.(*layers.IPv4)
if ip == nil {
continue
}
if ip.Version == 6 {
ip6p := gopacket.NewPacket(ip.LayerContents(), layers.LayerTypeIPv6, gopacket.Default)
p.Packet = ip6p
}
var pkt nfqueue.NFQPacket
pkt = *p
go fw.filterPacket(&pkt, timestamp)
} else {
p.Accept()
}
}
}()
for {
select {
case <-fw.reloadRulesChan:
fw.loadRules()
case <-fw.stopChan:
9 years ago
return
}
}
}
func Main() {
readConfig()
logBackend, logBackend2 := setupLoggerBackend(FirewallConfig.LoggingLevel)
if logBackend2 == nil {
logging.SetBackend(logBackend)
} else {
logging.SetBackend(logBackend, logBackend2)
}
procsnitch.SetLogger(log)
9 years ago
if os.Geteuid() != 0 {
log.Error("Must be run as root")
os.Exit(1)
}
setupIPTables()
9 years ago
ds, err := newDbusServer()
9 years ago
if err != nil {
log.Error(err.Error())
os.Exit(1)
}
fw := &Firewall{
dbus: ds,
8 years ago
dns: newDNSCache(),
enabled: true,
logBackend: logBackend,
policyMap: make(map[string]*Policy),
reloadRulesChan: make(chan bool, 0),
stopChan: make(chan bool, 0),
9 years ago
}
ds.fw = fw
go pcoroner.MonitorThread(procDeathCallbackDNS, fw.dns)
9 years ago
fw.loadRules()
fw.dbus.emitRefresh("init")
go OzReceiver(fw)
9 years ago
fw.runFilter()
// observe process signals and either
// reload rules or shutdown firewall service
sigKillChan := make(chan os.Signal, 1)
signal.Notify(sigKillChan, os.Interrupt, os.Kill)
sigHupChan := make(chan os.Signal, 1)
signal.Notify(sigHupChan, syscall.SIGHUP)
for {
select {
case <-sigHupChan:
fw.reloadRules()
case <-sigKillChan:
fw.stop()
return
}
}
9 years ago
}