diff --git a/fw-prompt/fw-prompt.go b/fw-prompt/fw-prompt.go index e50057a..0ad75ad 100644 --- a/fw-prompt/fw-prompt.go +++ b/fw-prompt/fw-prompt.go @@ -570,8 +570,9 @@ func clearEditor() { chkGroup.SetActive(false) } -func removeSelectedRule(idx int) error { +func removeSelectedRule(idx int, rmdecision bool) error { fmt.Println("XXX: attempting to remove idx = ", idx) + path, err := gtk.TreePathNewFromString(fmt.Sprintf("%d", idx)) if err != nil { return err @@ -582,14 +583,12 @@ func removeSelectedRule(idx int) error { return err } - ok := globalLS.Remove(iter) + globalLS.Remove(iter) - // XXX: hmmm? why does this work? shouldn't it be the opposite? - if ok { - return errors.New("Unexpected error removing rule from list") + if rmdecision { + decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...) } - decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...) toggleHover() return nil } @@ -879,7 +878,7 @@ func main() { fmt.Println("RULESTR = ", rulestr) makeDecision(idx, rulestr, int(rule.Scope)) fmt.Println("Decision made.") - err = removeSelectedRule(idx) + err = removeSelectedRule(idx, true) if err == nil { clearEditor() } else { @@ -905,7 +904,7 @@ func main() { fmt.Println("RULESTR = ", rulestr) makeDecision(idx, rulestr, int(rule.Scope)) fmt.Println("Decision made.") - err = removeSelectedRule(idx) + err = removeSelectedRule(idx, true) if err == nil { clearEditor() } else { @@ -922,7 +921,7 @@ func main() { makeDecision(idx, "", 0) fmt.Println("Decision made.") - err = removeSelectedRule(idx) + err = removeSelectedRule(idx, true) if err == nil { clearEditor() } else { diff --git a/gnome-shell/firewall@subgraph.com/extension.js b/gnome-shell/firewall@subgraph.com/extension.js index 73c743f..ff3b0c1 100644 --- a/gnome-shell/firewall@subgraph.com/extension.js +++ b/gnome-shell/firewall@subgraph.com/extension.js @@ -93,7 +93,7 @@ const FirewallPromptHandler = new Lang.Class({ RequestPromptAsync: function(params, invocation) { 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._invocation = invocation; this._dialog.update(app, icon, path, address, port, ip, origin, uid, gid, user, group, pid, proto, optstring, expanded, expert, action); diff --git a/sgfw/policy.go b/sgfw/policy.go index ae76142..ea1f0cb 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -24,7 +24,7 @@ var _interpreters = []string{ "bash", } -type sandboxRule struct { +/*type sandboxRule struct { SrcIf net.IP DstIP net.IP DstPort uint16 @@ -33,7 +33,7 @@ type sandboxRule struct { var sandboxRules = []sandboxRule { // { net.IP{172,16,1,42}, net.IP{140,211,166,134}, 21, false }, -} +} */ type pendingConnection interface { policy() *Policy @@ -47,6 +47,8 @@ type pendingConnection interface { dstPort() uint16 accept() drop() + setPrompting(bool) + getPrompting() bool print() string } @@ -56,6 +58,7 @@ type pendingPkt struct { pkt *nfqueue.NFQPacket pinfo *procsnitch.Info optstring string + prompting bool } func getEmptyPInfo() *procsnitch.Info { @@ -152,6 +155,14 @@ func (pp *pendingPkt) drop() { 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 { 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: pkt.Accept() 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: 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) { p.pendingQueue = append(p.pendingQueue, pc) - if !p.promptInProgress { +fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress) + if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { p.promptInProgress = true go p.fw.dbus.prompt(p) } } -func (p *Policy) nextPending() pendingConnection { +func (p *Policy) nextPending() (pendingConnection, bool) { p.lock.Lock() +fmt.Println("nextPending(): len = ", len(p.pendingQueue)) defer p.lock.Unlock() + if !DoMultiPrompt { + if len(p.pendingQueue) == 0 { + return nil, true + } + return p.pendingQueue[0], false + } + 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) { diff --git a/sgfw/prompt.go b/sgfw/prompt.go index 3acec27..fcd154e 100644 --- a/sgfw/prompt.go +++ b/sgfw/prompt.go @@ -10,6 +10,12 @@ import ( "github.com/godbus/dbus" ) + +var DoMultiPrompt = true +const MAX_PROMPTS = 3 +var outstandingPrompts = 0 +var promptLock = &sync.Mutex{} + func newPrompter(conn *dbus.Conn) *prompter { p := new(prompter) p.cond = sync.NewCond(&p.lock) @@ -42,27 +48,86 @@ func (p *prompter) prompt(policy *Policy) { func (p *prompter) promptLoop() { p.lock.Lock() for { +fmt.Println("promptLoop() outer") for p.processNextPacket() { +fmt.Println("promptLoop() inner") } +fmt.Println("promptLoop() wait") p.cond.Wait() } } func (p *prompter) processNextPacket() bool { - pc := p.nextConnection() - if pc == nil { - return false + var pc pendingConnection = nil + + 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() 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 } +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) { var scope int32 var rule string + if DoMultiPrompt { + defer processReturn(pc) + } + addr := pc.hostname() if addr == "" { addr = pc.dst().String() @@ -124,23 +189,35 @@ func (p *prompter) processConnection(pc pendingConnection) { dbusp.alertRule("sgfw prompt added new rule") } -func (p *prompter) nextConnection() pendingConnection { +func (p *prompter) nextConnection() (pendingConnection, bool) { +fmt.Println("nextConnection()") for { if len(p.policyQueue) == 0 { - return nil + return nil, true } policy := p.policyQueue[0] - pc := policy.nextPending() - if pc == nil { + pc, qempty := policy.nextPending() + if pc == nil && qempty { p.removePolicy(policy) } else { - return pc + return pc, qempty } } } 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 { if pol != policy { newQueue = append(newQueue, pol) diff --git a/sgfw/socks_server_chain.go b/sgfw/socks_server_chain.go index 4ddc01e..4528aea 100644 --- a/sgfw/socks_server_chain.go +++ b/sgfw/socks_server_chain.go @@ -51,6 +51,7 @@ type pendingSocksConnection struct { destPort uint16 pinfo *procsnitch.Info verdict chan int + prompting bool } 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) getPrompting() bool { return sc.prompting } + +func (sc *pendingSocksConnection) setPrompting(val bool) { sc.prompting = val } + func (sc *pendingSocksConnection) print() string { return "socks connection" } func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain { @@ -247,6 +252,7 @@ func (c *socksChainSession) filterConnect() bool { destPort: port, pinfo: pinfo, verdict: make(chan int), + prompting: false, } policy.processPromptResult(pending) v := <-pending.verdict