|
|
@ -6,26 +6,77 @@ import (
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/subgraph/fw-daemon/nfqueue"
|
|
|
|
"github.com/subgraph/fw-daemon/nfqueue"
|
|
|
|
"github.com/subgraph/go-procsnitch"
|
|
|
|
"github.com/subgraph/go-procsnitch"
|
|
|
|
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type pendingConnection interface {
|
|
|
|
|
|
|
|
policy() *Policy
|
|
|
|
|
|
|
|
procInfo() *procsnitch.Info
|
|
|
|
|
|
|
|
hostname() string
|
|
|
|
|
|
|
|
dst() net.IP
|
|
|
|
|
|
|
|
dstPort() uint16
|
|
|
|
|
|
|
|
accept()
|
|
|
|
|
|
|
|
drop()
|
|
|
|
|
|
|
|
print() string
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type pendingPkt struct {
|
|
|
|
type pendingPkt struct {
|
|
|
|
policy *Policy
|
|
|
|
pol *Policy
|
|
|
|
hostname string
|
|
|
|
name string
|
|
|
|
pkt *nfqueue.Packet
|
|
|
|
pkt *nfqueue.Packet
|
|
|
|
pinfo *procsnitch.Info
|
|
|
|
pinfo *procsnitch.Info
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) policy() *Policy {
|
|
|
|
|
|
|
|
return pp.pol
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) procInfo() *procsnitch.Info {
|
|
|
|
|
|
|
|
return pp.pinfo
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) hostname() string {
|
|
|
|
|
|
|
|
return pp.name
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pp *pendingPkt) dst() net.IP {
|
|
|
|
|
|
|
|
return pp.pkt.Dst
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) dstPort() uint16 {
|
|
|
|
|
|
|
|
return pp.pkt.DstPort
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) accept() {
|
|
|
|
|
|
|
|
pp.pkt.Accept()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) drop() {
|
|
|
|
|
|
|
|
pp.pkt.Mark = 1
|
|
|
|
|
|
|
|
pp.pkt.Accept()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (pp *pendingPkt) print() string {
|
|
|
|
|
|
|
|
return printPacket(pp.pkt, pp.name)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type Policy struct {
|
|
|
|
type Policy struct {
|
|
|
|
fw *Firewall
|
|
|
|
fw *Firewall
|
|
|
|
path string
|
|
|
|
path string
|
|
|
|
application string
|
|
|
|
application string
|
|
|
|
icon string
|
|
|
|
icon string
|
|
|
|
rules RuleList
|
|
|
|
rules RuleList
|
|
|
|
pendingQueue []*pendingPkt
|
|
|
|
pendingQueue []pendingConnection
|
|
|
|
promptInProgress bool
|
|
|
|
promptInProgress bool
|
|
|
|
lock sync.Mutex
|
|
|
|
lock sync.Mutex
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (fw *Firewall) PolicyForPath(path string) *Policy {
|
|
|
|
|
|
|
|
fw.lock.Lock()
|
|
|
|
|
|
|
|
defer fw.lock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fw.policyForPath(path)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (fw *Firewall) policyForPath(path string) *Policy {
|
|
|
|
func (fw *Firewall) policyForPath(path string) *Policy {
|
|
|
|
if _, ok := fw.policyMap[path]; !ok {
|
|
|
|
if _, ok := fw.policyMap[path]; !ok {
|
|
|
|
p := new(Policy)
|
|
|
|
p := new(Policy)
|
|
|
@ -50,7 +101,7 @@ func (p *Policy) processPacket(pkt *nfqueue.Packet, pinfo *procsnitch.Info) {
|
|
|
|
if !logRedact {
|
|
|
|
if !logRedact {
|
|
|
|
log.Info("Lookup(%s): %s", pkt.Dst.String(), name)
|
|
|
|
log.Info("Lookup(%s): %s", pkt.Dst.String(), name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result := p.rules.filter(pkt, pinfo, name)
|
|
|
|
result := p.rules.filterPacket(pkt, pinfo, name)
|
|
|
|
switch result {
|
|
|
|
switch result {
|
|
|
|
case FILTER_DENY:
|
|
|
|
case FILTER_DENY:
|
|
|
|
pkt.Mark = 1
|
|
|
|
pkt.Mark = 1
|
|
|
@ -58,21 +109,21 @@ func (p *Policy) processPacket(pkt *nfqueue.Packet, pinfo *procsnitch.Info) {
|
|
|
|
case FILTER_ALLOW:
|
|
|
|
case FILTER_ALLOW:
|
|
|
|
pkt.Accept()
|
|
|
|
pkt.Accept()
|
|
|
|
case FILTER_PROMPT:
|
|
|
|
case FILTER_PROMPT:
|
|
|
|
p.processPromptResult(&pendingPkt{policy: p, hostname: name, pkt: pkt, pinfo: pinfo})
|
|
|
|
p.processPromptResult(&pendingPkt{pol: p, name: name, pkt: pkt, pinfo: pinfo})
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
log.Warning("Unexpected filter result: %d", result)
|
|
|
|
log.Warning("Unexpected filter result: %d", result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Policy) processPromptResult(pp *pendingPkt) {
|
|
|
|
func (p *Policy) processPromptResult(pc pendingConnection) {
|
|
|
|
p.pendingQueue = append(p.pendingQueue, pp)
|
|
|
|
p.pendingQueue = append(p.pendingQueue, pc)
|
|
|
|
if !p.promptInProgress {
|
|
|
|
if !p.promptInProgress {
|
|
|
|
p.promptInProgress = true
|
|
|
|
p.promptInProgress = true
|
|
|
|
go p.fw.dbus.prompt(p)
|
|
|
|
go p.fw.dbus.prompt(p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Policy) nextPending() *pendingPkt {
|
|
|
|
func (p *Policy) nextPending() pendingConnection {
|
|
|
|
p.lock.Lock()
|
|
|
|
p.lock.Lock()
|
|
|
|
defer p.lock.Unlock()
|
|
|
|
defer p.lock.Unlock()
|
|
|
|
if len(p.pendingQueue) == 0 {
|
|
|
|
if len(p.pendingQueue) == 0 {
|
|
|
@ -81,14 +132,14 @@ func (p *Policy) nextPending() *pendingPkt {
|
|
|
|
return p.pendingQueue[0]
|
|
|
|
return p.pendingQueue[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Policy) removePending(pp *pendingPkt) {
|
|
|
|
func (p *Policy) removePending(pc pendingConnection) {
|
|
|
|
p.lock.Lock()
|
|
|
|
p.lock.Lock()
|
|
|
|
defer p.lock.Unlock()
|
|
|
|
defer p.lock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
remaining := []*pendingPkt{}
|
|
|
|
remaining := []pendingConnection{}
|
|
|
|
for _, pkt := range p.pendingQueue {
|
|
|
|
for _, c := range p.pendingQueue {
|
|
|
|
if pkt != pp {
|
|
|
|
if c != pc {
|
|
|
|
remaining = append(remaining, pkt)
|
|
|
|
remaining = append(remaining, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(remaining) != len(p.pendingQueue) {
|
|
|
|
if len(remaining) != len(p.pendingQueue) {
|
|
|
@ -141,18 +192,17 @@ func (p *Policy) removeRule(r *Rule) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p *Policy) filterPending(rule *Rule) {
|
|
|
|
func (p *Policy) filterPending(rule *Rule) {
|
|
|
|
remaining := []*pendingPkt{}
|
|
|
|
remaining := []pendingConnection{}
|
|
|
|
for _, pp := range p.pendingQueue {
|
|
|
|
for _, pc := range p.pendingQueue {
|
|
|
|
if rule.match(pp.pkt, pp.hostname) {
|
|
|
|
if rule.match(pc.dst(), pc.dstPort(), pc.hostname()) {
|
|
|
|
log.Info("Also applying %s to %s", rule.getString(logRedact), printPacket(pp.pkt, pp.hostname))
|
|
|
|
log.Info("Also applying %s to %s", rule.getString(logRedact), pc.print())
|
|
|
|
if rule.rtype == RULE_ALLOW {
|
|
|
|
if rule.rtype == RULE_ALLOW {
|
|
|
|
pp.pkt.Accept()
|
|
|
|
pc.accept()
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
pp.pkt.Mark = 1
|
|
|
|
pc.drop()
|
|
|
|
pp.pkt.Accept()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
remaining = append(remaining, pp)
|
|
|
|
remaining = append(remaining, pc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(remaining) != len(p.pendingQueue) {
|
|
|
|
if len(remaining) != len(p.pendingQueue) {
|
|
|
@ -208,9 +258,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.Packet) {
|
|
|
|
pkt.Accept()
|
|
|
|
pkt.Accept()
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fw.lock.Lock()
|
|
|
|
policy := fw.PolicyForPath(pinfo.ExePath)
|
|
|
|
policy := fw.policyForPath(pinfo.ExePath)
|
|
|
|
|
|
|
|
fw.lock.Unlock()
|
|
|
|
|
|
|
|
policy.processPacket(pkt, pinfo)
|
|
|
|
policy.processPacket(pkt, pinfo)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|