Very noisy, experimental support for asynchronous multi-rule firewall prompting.

Fixed prompted rule removal bug in fw-prompt.
shw_dev
shw 8 years ago
parent 3319802a80
commit 5f5042fed4

@ -570,8 +570,9 @@ func clearEditor() {
chkGroup.SetActive(false) chkGroup.SetActive(false)
} }
func removeSelectedRule(idx int) error { func removeSelectedRule(idx int, rmdecision bool) error {
fmt.Println("XXX: attempting to remove idx = ", idx) fmt.Println("XXX: attempting to remove idx = ", idx)
path, err := gtk.TreePathNewFromString(fmt.Sprintf("%d", idx)) path, err := gtk.TreePathNewFromString(fmt.Sprintf("%d", idx))
if err != nil { if err != nil {
return err return err
@ -582,14 +583,12 @@ func removeSelectedRule(idx int) error {
return err return err
} }
ok := globalLS.Remove(iter) globalLS.Remove(iter)
// XXX: hmmm? why does this work? shouldn't it be the opposite? if rmdecision {
if ok { decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...)
return errors.New("Unexpected error removing rule from list")
} }
decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...)
toggleHover() toggleHover()
return nil return nil
} }
@ -879,7 +878,7 @@ func main() {
fmt.Println("RULESTR = ", rulestr) fmt.Println("RULESTR = ", rulestr)
makeDecision(idx, rulestr, int(rule.Scope)) makeDecision(idx, rulestr, int(rule.Scope))
fmt.Println("Decision made.") fmt.Println("Decision made.")
err = removeSelectedRule(idx) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
} else { } else {
@ -905,7 +904,7 @@ func main() {
fmt.Println("RULESTR = ", rulestr) fmt.Println("RULESTR = ", rulestr)
makeDecision(idx, rulestr, int(rule.Scope)) makeDecision(idx, rulestr, int(rule.Scope))
fmt.Println("Decision made.") fmt.Println("Decision made.")
err = removeSelectedRule(idx) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
} else { } else {
@ -922,7 +921,7 @@ func main() {
makeDecision(idx, "", 0) makeDecision(idx, "", 0)
fmt.Println("Decision made.") fmt.Println("Decision made.")
err = removeSelectedRule(idx) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
} else { } else {

@ -93,7 +93,7 @@ const FirewallPromptHandler = new Lang.Class({
RequestPromptAsync: function(params, invocation) { RequestPromptAsync: function(params, invocation) {
let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, optstring, expanded, expert, action] = params; let [app, icon, path, address, port, ip, origin, proto, uid, gid, user, group, pid, optstring, expanded, expert, action] = params;
this._closeDialog(); // this._closeDialog();
this._dialog = new Dialog.PromptDialog(invocation); this._dialog = new Dialog.PromptDialog(invocation);
this._invocation = invocation; this._invocation = invocation;
this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action); this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action);

@ -24,7 +24,7 @@ var _interpreters = []string{
"bash", "bash",
} }
type sandboxRule struct { /*type sandboxRule struct {
SrcIf net.IP SrcIf net.IP
DstIP net.IP DstIP net.IP
DstPort uint16 DstPort uint16
@ -33,7 +33,7 @@ type sandboxRule struct {
var sandboxRules = []sandboxRule { var sandboxRules = []sandboxRule {
// { net.IP{172,16,1,42}, net.IP{140,211,166,134}, 21, false }, // { net.IP{172,16,1,42}, net.IP{140,211,166,134}, 21, false },
} } */
type pendingConnection interface { type pendingConnection interface {
policy() *Policy policy() *Policy
@ -47,6 +47,8 @@ type pendingConnection interface {
dstPort() uint16 dstPort() uint16
accept() accept()
drop() drop()
setPrompting(bool)
getPrompting() bool
print() string print() string
} }
@ -56,6 +58,7 @@ type pendingPkt struct {
pkt *nfqueue.NFQPacket pkt *nfqueue.NFQPacket
pinfo *procsnitch.Info pinfo *procsnitch.Info
optstring string optstring string
prompting bool
} }
func getEmptyPInfo() *procsnitch.Info { func getEmptyPInfo() *procsnitch.Info {
@ -152,6 +155,14 @@ func (pp *pendingPkt) drop() {
pp.pkt.Accept() pp.pkt.Accept()
} }
func (pp *pendingPkt) getPrompting() bool {
return pp.prompting
}
func (pp *pendingPkt) setPrompting(val bool) {
pp.prompting = val
}
func (pp *pendingPkt) print() string { func (pp *pendingPkt) print() string {
return printPacket(pp.pkt, pp.name, pp.pinfo) return printPacket(pp.pkt, pp.name, pp.pinfo)
} }
@ -216,7 +227,7 @@ func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, o
case FILTER_ALLOW: case FILTER_ALLOW:
pkt.Accept() pkt.Accept()
case FILTER_PROMPT: case FILTER_PROMPT:
p.processPromptResult(&pendingPkt{pol: p, name: name, pkt: pkt, pinfo: pinfo, optstring: optstr}) p.processPromptResult(&pendingPkt{pol: p, name: name, pkt: pkt, pinfo: pinfo, optstring: optstr, prompting: false})
default: default:
log.Warningf("Unexpected filter result: %d", result) log.Warningf("Unexpected filter result: %d", result)
} }
@ -224,19 +235,41 @@ func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, o
func (p *Policy) processPromptResult(pc pendingConnection) { func (p *Policy) processPromptResult(pc pendingConnection) {
p.pendingQueue = append(p.pendingQueue, pc) p.pendingQueue = append(p.pendingQueue, pc)
if !p.promptInProgress { fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress)
if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) {
p.promptInProgress = true p.promptInProgress = true
go p.fw.dbus.prompt(p) go p.fw.dbus.prompt(p)
} }
} }
func (p *Policy) nextPending() pendingConnection { func (p *Policy) nextPending() (pendingConnection, bool) {
p.lock.Lock() p.lock.Lock()
fmt.Println("nextPending(): len = ", len(p.pendingQueue))
defer p.lock.Unlock() defer p.lock.Unlock()
if !DoMultiPrompt {
if len(p.pendingQueue) == 0 {
return nil, true
}
return p.pendingQueue[0], false
}
if len(p.pendingQueue) == 0 { if len(p.pendingQueue) == 0 {
return nil return nil, true
} }
return p.pendingQueue[0]
// for len(p.pendingQueue) != 0 {
fmt.Println("nextPending() loop: len = ", len(p.pendingQueue))
for i := 0; i < len(p.pendingQueue); i++ {
fmt.Printf("pendingqueue %v: %v\n", i, p.pendingQueue[i].getPrompting())
if !p.pendingQueue[i].getPrompting() {
return p.pendingQueue[i], false
}
}
// }
fmt.Println("nextPending() returning")
return nil, false
} }
func (p *Policy) removePending(pc pendingConnection) { func (p *Policy) removePending(pc pendingConnection) {

@ -10,6 +10,12 @@ import (
"github.com/godbus/dbus" "github.com/godbus/dbus"
) )
var DoMultiPrompt = true
const MAX_PROMPTS = 3
var outstandingPrompts = 0
var promptLock = &sync.Mutex{}
func newPrompter(conn *dbus.Conn) *prompter { func newPrompter(conn *dbus.Conn) *prompter {
p := new(prompter) p := new(prompter)
p.cond = sync.NewCond(&p.lock) p.cond = sync.NewCond(&p.lock)
@ -42,27 +48,86 @@ func (p *prompter) prompt(policy *Policy) {
func (p *prompter) promptLoop() { func (p *prompter) promptLoop() {
p.lock.Lock() p.lock.Lock()
for { for {
fmt.Println("promptLoop() outer")
for p.processNextPacket() { for p.processNextPacket() {
fmt.Println("promptLoop() inner")
} }
fmt.Println("promptLoop() wait")
p.cond.Wait() p.cond.Wait()
} }
} }
func (p *prompter) processNextPacket() bool { func (p *prompter) processNextPacket() bool {
pc := p.nextConnection() var pc pendingConnection = nil
if pc == nil {
return false if !DoMultiPrompt {
pc, _ = p.nextConnection()
if pc == nil {
return false
}
p.lock.Unlock()
defer p.lock.Lock()
p.processConnection(pc)
return true
}
empty := true
for {
pc, empty = p.nextConnection()
fmt.Println("processNextPacket() loop; empty = ", empty, " / pc = ", pc)
if pc == nil && empty {
return false
} else if pc == nil {
continue
} else if pc != nil {
break
}
} }
p.lock.Unlock() p.lock.Unlock()
defer p.lock.Lock() defer p.lock.Lock()
p.processConnection(pc) fmt.Println("Waiting for prompt lock go...")
for {
promptLock.Lock()
if outstandingPrompts >= MAX_PROMPTS {
promptLock.Unlock()
continue
}
if pc.getPrompting() {
fmt.Println("Skipping over already prompted connection")
promptLock.Unlock()
continue
}
break
}
fmt.Println("Passed prompt lock!")
outstandingPrompts++
fmt.Println("Incremented outstanding to ", outstandingPrompts)
promptLock.Unlock()
// if !pc.getPrompting() {
pc.setPrompting(true)
go p.processConnection(pc)
// }
return true return true
} }
func processReturn (pc pendingConnection) {
promptLock.Lock()
outstandingPrompts--
fmt.Println("Return decremented outstanding to ", outstandingPrompts)
promptLock.Unlock()
pc.setPrompting(false)
}
func (p *prompter) processConnection(pc pendingConnection) { func (p *prompter) processConnection(pc pendingConnection) {
var scope int32 var scope int32
var rule string var rule string
if DoMultiPrompt {
defer processReturn(pc)
}
addr := pc.hostname() addr := pc.hostname()
if addr == "" { if addr == "" {
addr = pc.dst().String() addr = pc.dst().String()
@ -124,23 +189,35 @@ func (p *prompter) processConnection(pc pendingConnection) {
dbusp.alertRule("sgfw prompt added new rule") dbusp.alertRule("sgfw prompt added new rule")
} }
func (p *prompter) nextConnection() pendingConnection { func (p *prompter) nextConnection() (pendingConnection, bool) {
fmt.Println("nextConnection()")
for { for {
if len(p.policyQueue) == 0 { if len(p.policyQueue) == 0 {
return nil return nil, true
} }
policy := p.policyQueue[0] policy := p.policyQueue[0]
pc := policy.nextPending() pc, qempty := policy.nextPending()
if pc == nil { if pc == nil && qempty {
p.removePolicy(policy) p.removePolicy(policy)
} else { } else {
return pc return pc, qempty
} }
} }
} }
func (p *prompter) removePolicy(policy *Policy) { func (p *prompter) removePolicy(policy *Policy) {
newQueue := make([]*Policy, 0, len(p.policyQueue)-1) var newQueue []*Policy = nil
if DoMultiPrompt {
if len(p.policyQueue) == 0 {
fmt.Println("Skipping over zero length policy queue")
newQueue = make([]*Policy, 0, 0)
}
}
if !DoMultiPrompt || newQueue == nil {
newQueue = make([]*Policy, 0, len(p.policyQueue)-1)
}
for _, pol := range p.policyQueue { for _, pol := range p.policyQueue {
if pol != policy { if pol != policy {
newQueue = append(newQueue, pol) newQueue = append(newQueue, pol)

@ -51,6 +51,7 @@ type pendingSocksConnection struct {
destPort uint16 destPort uint16
pinfo *procsnitch.Info pinfo *procsnitch.Info
verdict chan int verdict chan int
prompting bool
} }
func (sc *pendingSocksConnection) policy() *Policy { func (sc *pendingSocksConnection) policy() *Policy {
@ -95,6 +96,10 @@ func (sc *pendingSocksConnection) accept() { sc.deliverVerdict(socksVerdictAccep
func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) } func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) }
func (sc *pendingSocksConnection) getPrompting() bool { return sc.prompting }
func (sc *pendingSocksConnection) setPrompting(val bool) { sc.prompting = val }
func (sc *pendingSocksConnection) print() string { return "socks connection" } func (sc *pendingSocksConnection) print() string { return "socks connection" }
func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain { func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain {
@ -247,6 +252,7 @@ func (c *socksChainSession) filterConnect() bool {
destPort: port, destPort: port,
pinfo: pinfo, pinfo: pinfo,
verdict: make(chan int), verdict: make(chan int),
prompting: false,
} }
policy.processPromptResult(pending) policy.processPromptResult(pending)
v := <-pending.verdict v := <-pending.verdict

Loading…
Cancel
Save