*WORK IN PROGRESS*: New file descriptor monitor thread removes prompt requests if associated socket closes/dies before user reacts.

fw-prompt request entries are now properly tethered to their default rule scope included by SGFW.
pendingConnection now operates on prompter instead of raw DBus object.
Fixed prompter bug in cycling through pending connections.
Fixed inadequacies in SGFW rules parsing/error handling.
go fmt.
shw_dev
Stephen Watt 7 years ago
parent 2eac4c7dc5
commit 0d13c7bb9c

@ -0,0 +1,6 @@
fw-prompt:
This function needs to be updated because it no longer works:
func toggleHover() { mainWin.SetKeepAbove(len(decisionWaiters) > 0) }
new go-procsnitch vendor package changes should be pushed into main project

@ -55,7 +55,7 @@ func newDbusServer() (*dbusServer, error) {
func (ds *dbusServer) RequestPrompt(guid, application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string, func (ds *dbusServer) RequestPrompt(guid, application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string,
is_socks bool, optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) { is_socks bool, optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) {
log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s / ip = %s, is_socks = %v, action = %v\n", application, icon, path, address, ip, is_socks, action) log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s / ip = %s, is_socks = %v, action = %v\n", application, icon, path, address, ip, is_socks, action)
decision := addRequest(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox) decision := addRequest(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox, int(action))
log.Print("Waiting on decision...") log.Print("Waiting on decision...")
decision.Cond.L.Lock() decision.Cond.L.Lock()
for !decision.Ready { for !decision.Ready {
@ -69,7 +69,7 @@ func (ds *dbusServer) RequestPrompt(guid, application, icon, path, address strin
func (ds *dbusServer) RequestPromptAsync(guid, application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string, func (ds *dbusServer) RequestPromptAsync(guid, application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string,
is_socks bool, optstring string, expanded, expert bool, action int32) (bool, *dbus.Error) { is_socks bool, optstring string, expanded, expert bool, action int32) (bool, *dbus.Error) {
log.Printf("ASYNC request prompt: guid = %s, app = %s, icon = %s, path = %s, address = %s / ip = %s, is_socks = %v, action = %v\n", guid, application, icon, path, address, ip, is_socks, action) log.Printf("ASYNC request prompt: guid = %s, app = %s, icon = %s, path = %s, address = %s / ip = %s, is_socks = %v, action = %v\n", guid, application, icon, path, address, ip, is_socks, action)
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox) addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox, int(action))
return true, nil return true, nil
} }

@ -314,8 +314,8 @@ func createColumn(title string, id int) *gtk.TreeViewColumn {
} }
func createListStore(general bool) *gtk.ListStore { func createListStore(general bool) *gtk.ListStore {
colData := []glib.Type{glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_INT, colData := []glib.Type{glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_STRING,
glib.TYPE_STRING, glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_STRING} glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_INT}
listStore, err := gtk.ListStoreNew(colData...) listStore, err := gtk.ListStoreNew(colData...)
if err != nil { if err != nil {
@ -350,7 +350,8 @@ func removeRequest(listStore *gtk.ListStore, guid string) {
} }
func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) bool { func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int,
origin string, is_socks bool, optstring string, sandbox string, action int) bool {
duplicated := false duplicated := false
globalPromptLock.Lock() globalPromptLock.Lock()
@ -383,7 +384,8 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
return duplicated return duplicated
} }
func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) bool { func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int,
origin string, is_socks bool, optstring string, sandbox string, action int) bool {
if listStore == nil { if listStore == nil {
listStore = globalLS listStore = globalLS
waitTimes := []int{1, 2, 5, 10} waitTimes := []int{1, 2, 5, 10}
@ -410,7 +412,7 @@ func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, p
log.Fatal("SGFW prompter GUI failed to load for unknown reasons") log.Fatal("SGFW prompter GUI failed to load for unknown reasons")
} }
if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox) { if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox, action) {
fmt.Println("REQUEST WAS DUPLICATE") fmt.Println("REQUEST WAS DUPLICATE")
return false return false
} else { } else {
@ -428,7 +430,7 @@ func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, p
} }
} }
colVals := make([]interface{}, 14) colVals := make([]interface{}, 15)
colVals[0] = 1 colVals[0] = 1
colVals[1] = guid colVals[1] = guid
colVals[2] = path colVals[2] = path
@ -454,6 +456,7 @@ func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, p
} }
colVals[13] = optstring colVals[13] = optstring
colVals[14] = action
colNums := make([]int, len(colVals)) colNums := make([]int, len(colVals))
@ -472,7 +475,8 @@ func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, p
return true return true
} }
func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) *decisionWaiter { func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int,
origin string, is_socks bool, optstring string, sandbox string, action int) *decisionWaiter {
if listStore == nil { if listStore == nil {
listStore = globalLS listStore = globalLS
waitTimes := []int{1, 2, 5, 10} waitTimes := []int{1, 2, 5, 10}
@ -499,7 +503,7 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
log.Fatal("SGFW prompter GUI failed to load for unknown reasons") log.Fatal("SGFW prompter GUI failed to load for unknown reasons")
} }
if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox) { if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox, action) {
fmt.Println("REQUEST WAS DUPLICATE") fmt.Println("REQUEST WAS DUPLICATE")
decision := addDecision() decision := addDecision()
toggleHover() toggleHover()
@ -519,7 +523,7 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
} }
} }
colVals := make([]interface{}, 14) colVals := make([]interface{}, 15)
colVals[0] = 1 colVals[0] = 1
colVals[1] = guid colVals[1] = guid
colVals[2] = path colVals[2] = path
@ -545,6 +549,7 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
} }
colVals[13] = optstring colVals[13] = optstring
colVals[14] = action
colNums := make([]int, len(colVals)) colNums := make([]int, len(colVals))
@ -774,6 +779,7 @@ func createCurrentRule() (ruleColumns, error) {
rule.Uname, rule.Gname = "", "" rule.Uname, rule.Gname = "", ""
rule.ForceTLS = chkTLS.GetActive() rule.ForceTLS = chkTLS.GetActive()
/* Pid int /* Pid int
Origin string */ Origin string */
@ -915,6 +921,11 @@ func getRuleByIdx(idx int) (ruleColumns, *gtk.TreeIter, error) {
rule.IsSocks = true rule.IsSocks = true
} }
rule.Scope, err = lsGetInt(globalLS, iter, 14)
if err != nil {
return rule, nil, err
}
return rule, iter, nil return rule, iter, nil
} }
@ -953,7 +964,7 @@ func addPendingPrompts(rules []string) {
for _, rule := range rules { for _, rule := range rules {
fields := strings.Split(rule, "|") fields := strings.Split(rule, "|")
if len(fields) != 17 { if len(fields) != 18 {
log.Printf("Got saved prompt message with strange data: \"%s\"", rule) log.Printf("Got saved prompt message with strange data: \"%s\"", rule)
continue continue
} }
@ -1001,7 +1012,13 @@ func addPendingPrompts(rules []string) {
optstring := fields[16] optstring := fields[16]
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox) action, err := strconv.Atoi(fields[17])
if err != nil {
log.Println("Error converting action in pending prompt message to integer:", err)
continue
}
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox, action)
} }
} }
@ -1206,6 +1223,10 @@ func main() {
tv.AppendColumn(createColumn("Details", 13)) tv.AppendColumn(createColumn("Details", 13))
acol := createColumn("Scope", 14)
acol.SetVisible(false)
tv.AppendColumn(acol)
listStore := createListStore(true) listStore := createListStore(true)
globalLS = listStore globalLS = listStore
@ -1322,12 +1343,12 @@ func main() {
} }
editPort.SetText(strconv.Itoa(seldata.Port)) editPort.SetText(strconv.Itoa(seldata.Port))
radioOnce.SetActive(true) radioOnce.SetActive(seldata.Scope == int(sgfw.APPLY_ONCE))
radioProcess.SetActive(false)
radioProcess.SetSensitive(seldata.Pid > 0) radioProcess.SetSensitive(seldata.Pid > 0)
radioParent.SetActive(false) radioParent.SetActive(false)
radioSession.SetActive(false) radioSession.SetActive(seldata.Scope == int(sgfw.APPLY_SESSION))
radioPermanent.SetActive(false) radioPermanent.SetActive(seldata.Scope == int(sgfw.APPLY_FOREVER))
comboProto.SetActiveID(seldata.Proto) comboProto.SetActiveID(seldata.Proto)
chkTLS.SetActive(seldata.IsSocks) chkTLS.SetActive(seldata.IsSocks)

@ -241,7 +241,8 @@ func (ds *dbusServer) GetPendingRequests(policy string) ([]string, *dbus.Error)
pstr += strconv.FormatInt(int64(pc.procInfo().Pid), 10) + "|" pstr += strconv.FormatInt(int64(pc.procInfo().Pid), 10) + "|"
pstr += pc.sandbox() + "|" pstr += pc.sandbox() + "|"
pstr += strconv.FormatBool(pc.socks()) + "|" pstr += strconv.FormatBool(pc.socks()) + "|"
pstr += pc.getOptString() pstr += pc.getOptString() + "|"
pstr += strconv.FormatUint(uint64(FirewallConfig.DefaultActionID), 10)
pending_data = append(pending_data, pstr) pending_data = append(pending_data, pstr)
} }
@ -334,10 +335,10 @@ func (ds *dbusServer) SetConfig(key string, val dbus.Variant) *dbus.Error {
return nil return nil
} }
func (ds *dbusServer) prompt(p *Policy) { /*func (ds *dbusServer) prompt(p *Policy) {
log.Info("prompting...") log.Info("prompting...")
ds.prompter.prompt(p) ds.prompter.prompt(p)
} } */
func (ob *dbusObjectP) alertRule(data string) { func (ob *dbusObjectP) alertRule(data string) {
ob.Call("com.subgraph.fwprompt.EventNotifier.Alert", 0, data) ob.Call("com.subgraph.fwprompt.EventNotifier.Alert", 0, data)

@ -50,8 +50,8 @@ type pendingConnection interface {
drop() drop()
setPrompting(bool) setPrompting(bool)
getPrompting() bool getPrompting() bool
setPrompter(*dbusObjectP) setPrompter(*prompter)
getPrompter() *dbusObjectP getPrompter() *prompter
getGUID() string getGUID() string
print() string print() string
} }
@ -63,7 +63,7 @@ type pendingPkt struct {
pinfo *procsnitch.Info pinfo *procsnitch.Info
optstring string optstring string
prompting bool prompting bool
prompter *dbusObjectP prompter *prompter
guid string guid string
} }
@ -183,11 +183,11 @@ func (pp *pendingPkt) drop() {
pp.pkt.Accept() pp.pkt.Accept()
} }
func (pp *pendingPkt) setPrompter(val *dbusObjectP) { func (pp *pendingPkt) setPrompter(val *prompter) {
pp.prompter = val pp.prompter = val
} }
func (pp *pendingPkt) getPrompter() *dbusObjectP { func (pp *pendingPkt) getPrompter() *prompter {
return pp.prompter return pp.prompter
} }
@ -320,32 +320,24 @@ func (p *Policy) processPromptResult(pc pendingConnection) {
//if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { //if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) {
// if !p.promptInProgress { // if !p.promptInProgress {
p.promptInProgress = true p.promptInProgress = true
go p.fw.dbus.prompt(p) go p.fw.dbus.prompter.prompt(p)
// } // }
} }
func (p *Policy) nextPending() (pendingConnection, bool) { func (p *Policy) nextPending() (pendingConnection, bool) {
p.lock.Lock() p.lock.Lock()
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, true return nil, true
} }
// for len(p.pendingQueue) != 0 {
for i := 0; i < len(p.pendingQueue); i++ { for i := 0; i < len(p.pendingQueue); i++ {
fmt.Printf("pendingQueue %v of %v: %v\n", i, len(p.pendingQueue), p.pendingQueue[i]) fmt.Printf("pendingQueue %v of %v: %v\n", i, len(p.pendingQueue), p.pendingQueue[i])
if !p.pendingQueue[i].getPrompting() { if !p.pendingQueue[i].getPrompting() {
return p.pendingQueue[i], false return p.pendingQueue[i], false
} }
} }
// }
return nil, false return nil, false
} }
@ -421,7 +413,7 @@ func (p *Policy) filterPending(rule *Rule) {
if prompter == nil { if prompter == nil {
fmt.Println("-------- prompter = NULL") fmt.Println("-------- prompter = NULL")
} else { } else {
call := prompter.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, pc.getGUID()) call := prompter.dbusObj.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, pc.getGUID())
fmt.Println("CAAAAAAAAAAAAAAALL = ", call) fmt.Println("CAAAAAAAAAAAAAAALL = ", call)
} }

@ -3,10 +3,12 @@ package sgfw
import ( import (
"fmt" "fmt"
"net" "net"
"os"
"os/user" "os/user"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"syscall"
"time" "time"
"github.com/godbus/dbus" "github.com/godbus/dbus"
@ -35,6 +37,7 @@ func (p *prompter) prompt(policy *Policy) {
defer p.lock.Unlock() defer p.lock.Unlock()
_, ok := p.policyMap[policy.sandbox+"|"+policy.path] _, ok := p.policyMap[policy.sandbox+"|"+policy.path]
if ok { if ok {
p.cond.Signal()
return return
} }
p.policyMap[policy.sandbox+"|"+policy.path] = policy p.policyMap[policy.sandbox+"|"+policy.path] = policy
@ -44,21 +47,23 @@ func (p *prompter) prompt(policy *Policy) {
} }
func (p *prompter) promptLoop() { func (p *prompter) promptLoop() {
p.lock.Lock() // p.lock.Lock()
for { for {
// fmt.Println("XXX: promptLoop() outer") // fmt.Println("XXX: promptLoop() outer")
p.lock.Lock()
for p.processNextPacket() { for p.processNextPacket() {
// fmt.Println("XXX: promptLoop() inner") // fmt.Println("XXX: promptLoop() inner")
} }
p.lock.Unlock()
// fmt.Println("promptLoop() wait") // fmt.Println("promptLoop() wait")
p.cond.Wait() // p.cond.Wait()
} }
} }
func (p *prompter) processNextPacket() bool { func (p *prompter) processNextPacket() bool {
var pc pendingConnection = nil var pc pendingConnection = nil
if 1 == 2 { /* if 1 == 2 {
// if !DoMultiPrompt { // if !DoMultiPrompt {
pc, _ = p.nextConnection() pc, _ = p.nextConnection()
if pc == nil { if pc == nil {
@ -68,12 +73,12 @@ func (p *prompter) processNextPacket() bool {
defer p.lock.Lock() defer p.lock.Lock()
p.processConnection(pc) p.processConnection(pc)
return true return true
} } */
empty := true empty := true
for { for {
pc, empty = p.nextConnection() pc, empty = p.nextConnection()
// fmt.Println("XXX: processNextPacket() loop; empty = ", empty, " / pc = ", pc) fmt.Println("XXX: processNextPacket() loop; empty = ", empty, " / pc = ", pc)
if pc == nil && empty { if pc == nil && empty {
return false return false
} else if pc == nil { } else if pc == nil {
@ -85,27 +90,145 @@ func (p *prompter) processNextPacket() bool {
p.lock.Unlock() p.lock.Unlock()
defer p.lock.Lock() defer p.lock.Lock()
// fmt.Println("XXX: Waiting for prompt lock go...") // fmt.Println("XXX: Waiting for prompt lock go...")
for { if pc.getPrompting() {
log.Debugf("Skipping over already prompted connection")
if pc.getPrompting() {
log.Debugf("Skipping over already prompted connection")
continue
}
break
} }
pc.setPrompting(true) pc.setPrompting(true)
go p.processConnection(pc) go p.processConnection(pc)
return true return true
} }
type PC2FDMapping struct {
guid string
inode uint64
fd int
fdpath string
prompter *prompter
}
var PC2FDMap = map[string]PC2FDMapping{}
var PC2FDMapLock = &sync.Mutex{}
var PC2FDMapRunning = false
func monitorPromptFDs(pc pendingConnection) {
guid := pc.getGUID()
pid := pc.procInfo().Pid
inode := pc.procInfo().Inode
fd := pc.procInfo().FD
prompter := pc.getPrompter()
fmt.Printf("ADD TO MONITOR: %v | %v / %v / %v\n", pc.policy().application, guid, pid, fd)
if pid == -1 || fd == -1 || prompter == nil {
log.Warning("Unexpected error condition occurred while adding socket fd to monitor")
return
}
PC2FDMapLock.Lock()
defer PC2FDMapLock.Unlock()
fdpath := fmt.Sprintf("/proc/%d/fd/%d", pid, fd)
PC2FDMap[guid] = PC2FDMapping{guid: guid, inode: inode, fd: fd, fdpath: fdpath, prompter: prompter}
return
}
func monitorPromptFDLoop() {
fmt.Println("++++++++++= monitorPromptFDLoop()")
for true {
delete_guids := []string{}
PC2FDMapLock.Lock()
fmt.Println("++++ nentries = ", len(PC2FDMap))
for guid, fdmon := range PC2FDMap {
fmt.Println("ENTRY:", fdmon)
lsb, err := os.Stat(fdmon.fdpath)
if err != nil {
log.Warningf("Error looking up socket \"%s\": %v\n", fdmon.fdpath, err)
delete_guids = append(delete_guids, guid)
continue
}
sb, ok := lsb.Sys().(*syscall.Stat_t)
if !ok {
log.Warning("Not a syscall.Stat_t")
delete_guids = append(delete_guids, guid)
continue
}
inode := sb.Ino
fmt.Println("+++ INODE = ", inode)
if inode != fdmon.inode {
fmt.Printf("inode mismatch: %v vs %v\n", inode, fdmon.inode)
delete_guids = append(delete_guids, guid)
}
}
fmt.Println("guids to delete: ", delete_guids)
saved_mappings := []PC2FDMapping{}
for _, guid := range delete_guids {
saved_mappings = append(saved_mappings, PC2FDMap[guid])
delete(PC2FDMap, guid)
}
PC2FDMapLock.Unlock()
for _, mapping := range saved_mappings {
call := mapping.prompter.dbusObj.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, mapping.guid)
fmt.Println("DISPOSING CALL = ", call)
prompter := mapping.prompter
prompter.lock.Lock()
for _, policy := range prompter.policyQueue {
policy.lock.Lock()
pcind := 0
for pcind < len(policy.pendingQueue) {
if policy.pendingQueue[pcind].getGUID() == mapping.guid {
fmt.Println("-------------- found guid to remove")
policy.pendingQueue = append(policy.pendingQueue[:pcind], policy.pendingQueue[pcind+1:]...)
} else {
pcind++
}
}
policy.lock.Unlock()
}
prompter.lock.Unlock()
}
fmt.Println("++++++++++= monitorPromptFDLoop WAIT")
time.Sleep(5 * time.Second)
}
}
func (p *prompter) processConnection(pc pendingConnection) { func (p *prompter) processConnection(pc pendingConnection) {
var scope int32 var scope int32
var dres bool var dres bool
var rule string var rule string
if !PC2FDMapRunning {
PC2FDMapLock.Lock()
if !PC2FDMapRunning {
PC2FDMapRunning = true
PC2FDMapLock.Unlock()
go monitorPromptFDLoop()
}
}
if pc.getPrompter() == nil { if pc.getPrompter() == nil {
pc.setPrompter(&dbusObjectP{p.dbusObj}) pc.setPrompter(p)
} }
addr := pc.hostname() addr := pc.hostname()
@ -127,6 +250,7 @@ func (p *prompter) processConnection(pc pendingConnection) {
// fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans)) // fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans))
// fmt.Println("ABOUT TO CALL ASYNC PROMPT") // fmt.Println("ABOUT TO CALL ASYNC PROMPT")
monitorPromptFDs(pc)
call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPromptAsync", 0, call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPromptAsync", 0,
pc.getGUID(), pc.getGUID(),
policy.application, policy.application,
@ -300,15 +424,23 @@ func (p *prompter) processConnection(pc pendingConnection) {
} }
func (p *prompter) nextConnection() (pendingConnection, bool) { func (p *prompter) nextConnection() (pendingConnection, bool) {
for { pind := 0
if len(p.policyQueue) == 0 {
return nil, true if len(p.policyQueue) == 0 {
} return nil, true
policy := p.policyQueue[0] }
fmt.Println("policy queue len = ", len(p.policyQueue))
for pind < len(p.policyQueue) {
fmt.Printf("pind = %v of %v\n", pind, len(p.policyQueue))
policy := p.policyQueue[pind]
pc, qempty := policy.nextPending() pc, qempty := policy.nextPending()
if pc == nil && qempty { if pc == nil && qempty {
p.removePolicy(policy) p.removePolicy(policy)
continue
} else { } else {
pind++
// if pc == nil && !qempty { // if pc == nil && !qempty {
if len(policy.rulesPending) > 0 { if len(policy.rulesPending) > 0 {
@ -360,17 +492,24 @@ func (p *prompter) nextConnection() (pendingConnection, bool) {
dbusp.alertRule("sgfw prompt added new rule") dbusp.alertRule("sgfw prompt added new rule")
} }
// } }
if pc == nil && !qempty { if pc == nil && !qempty {
log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!") // log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!")
time.Sleep(time.Millisecond * 300) time.Sleep(time.Millisecond * 300)
} continue
}
if pc != nil && pc.getPrompting() {
fmt.Println("SKIPPING PROMPTED")
continue
} }
return pc, qempty return pc, qempty
} }
} }
return nil, true
} }
func (p *prompter) removePolicy(policy *Policy) { func (p *prompter) removePolicy(policy *Policy) {

@ -479,7 +479,10 @@ func (fw *Firewall) loadRules() {
if err != nil { if err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
log.Warningf("Failed to open %s for reading: %v", p, err) log.Warningf("Failed to open %s for reading: %v", p, err)
} else {
log.Warningf("Did not find a rules file at %s: SGFW loaded with no rules\n", p)
} }
return return
} }
var policy *Policy var policy *Policy
@ -497,7 +500,13 @@ func (fw *Firewall) loadRules() {
func (fw *Firewall) processPathLine(line string) *Policy { func (fw *Firewall) processPathLine(line string) *Policy {
pathLine := line[1 : len(line)-1] pathLine := line[1 : len(line)-1]
toks := strings.Split(pathLine, "|") toks := strings.Split(pathLine, "|")
if len(toks) != 2 {
log.Warning("Error parsing rules directive:", line)
return nil
}
policy := fw.policyForPathAndSandbox(toks[1], toks[0]) policy := fw.policyForPathAndSandbox(toks[1], toks[0])
policy.lock.Lock() policy.lock.Lock()
defer policy.lock.Unlock() defer policy.lock.Unlock()

@ -56,7 +56,7 @@ type pendingSocksConnection struct {
pinfo *procsnitch.Info pinfo *procsnitch.Info
verdict chan int verdict chan int
prompting bool prompting bool
prompter *dbusObjectP prompter *prompter
guid string guid string
optstr string optstr string
} }
@ -124,9 +124,9 @@ func (sc *pendingSocksConnection) acceptTLSOnly() { sc.deliverVerdict(socksVerdi
func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) } func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) }
func (sc *pendingSocksConnection) setPrompter(val *dbusObjectP) { sc.prompter = val } func (sc *pendingSocksConnection) setPrompter(val *prompter) { sc.prompter = val }
func (sc *pendingSocksConnection) getPrompter() *dbusObjectP { return sc.prompter } func (sc *pendingSocksConnection) getPrompter() *prompter { return sc.prompter }
func (sc *pendingSocksConnection) getGUID() string { func (sc *pendingSocksConnection) getGUID() string {
if sc.guid == "" { if sc.guid == "" {

@ -1,8 +1,8 @@
package procsnitch package procsnitch
import ( import (
"encoding/hex"
"encoding/binary" "encoding/binary"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"github.com/op/go-logging" "github.com/op/go-logging"
@ -169,7 +169,7 @@ func ParseIP(ip string) (net.IP, error) {
} }
if isLittleEndian > 0 { if isLittleEndian > 0 {
for i := 0; i < len(dst) / 4; i++ { for i := 0; i < len(dst)/4; i++ {
start, end := i*4, (i+1)*4 start, end := i*4, (i+1)*4
word := dst[start:end] word := dst[start:end]
lval := binary.LittleEndian.Uint32(word) lval := binary.LittleEndian.Uint32(word)
@ -177,13 +177,13 @@ func ParseIP(ip string) (net.IP, error) {
} }
} }
/* if len(dst) == 16 { /* if len(dst) == 16 {
dst2 := []byte{dst[3], dst[2], dst[1], dst[0], dst[7], dst[6], dst[5], dst[4], dst[11], dst[10], dst[9], dst[8], dst[15], dst[14], dst[13], dst[12]} dst2 := []byte{dst[3], dst[2], dst[1], dst[0], dst[7], dst[6], dst[5], dst[4], dst[11], dst[10], dst[9], dst[8], dst[15], dst[14], dst[13], dst[12]}
return net.IP(dst2), nil return net.IP(dst2), nil
} }
for i, j := 0, len(dst)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(dst)-1; i < j; i, j = i+1, j-1 {
dst[i], dst[j] = dst[j], dst[i] dst[i], dst[j] = dst[j], dst[i]
} */ } */
return net.IP(dst), nil return net.IP(dst), nil
} }
@ -312,6 +312,7 @@ func stripLabel(s string) string {
// stolen from github.com/virtao/GoEndian // stolen from github.com/virtao/GoEndian
const INT_SIZE int = int(unsafe.Sizeof(0)) const INT_SIZE int = int(unsafe.Sizeof(0))
func setEndian() { func setEndian() {
var i int = 0x1 var i int = 0x1
bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i)) bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i))

@ -23,7 +23,9 @@ type Info struct {
FirstArg string FirstArg string
ParentCmdLine string ParentCmdLine string
ParentExePath string ParentExePath string
Sandbox string Sandbox string
Inode uint64
FD int
} }
type pidCache struct { type pidCache struct {
@ -51,10 +53,12 @@ func loadCache() map[uint64]*Info {
for _, n := range readdir("/proc") { for _, n := range readdir("/proc") {
pid := toPid(n) pid := toPid(n)
if pid != 0 { if pid != 0 {
pinfo := &Info{Pid: pid} inodes, fds := inodesFromPid(pid)
for _, inode := range inodesFromPid(pid) { for iind, inode := range inodes {
pinfo := &Info{Inode: inode, Pid: pid, FD: fds[iind]}
cmap[inode] = pinfo cmap[inode] = pinfo
} }
} }
} }
return cmap return cmap
@ -76,8 +80,9 @@ func toPid(name string) int {
return (int)(pid) return (int)(pid)
} }
func inodesFromPid(pid int) []uint64 { func inodesFromPid(pid int) ([]uint64, []int) {
var inodes []uint64 var inodes []uint64
var fds []int
fdpath := fmt.Sprintf("/proc/%d/fd", pid) fdpath := fmt.Sprintf("/proc/%d/fd", pid)
for _, n := range readdir(fdpath) { for _, n := range readdir(fdpath) {
if link, err := os.Readlink(path.Join(fdpath, n)); err != nil { if link, err := os.Readlink(path.Join(fdpath, n)); err != nil {
@ -85,12 +90,19 @@ func inodesFromPid(pid int) []uint64 {
log.Warningf("Error reading link %s: %v", n, err) log.Warningf("Error reading link %s: %v", n, err)
} }
} else { } else {
fd, err := strconv.Atoi(n)
if err != nil {
log.Warningf("Error retrieving fd associated with pid %v: %v", pid, err)
fd = -1
}
if inode := extractSocket(link); inode > 0 { if inode := extractSocket(link); inode > 0 {
inodes = append(inodes, inode) inodes = append(inodes, inode)
fds = append(fds, fd)
} }
} }
} }
return inodes return inodes, fds
} }
func extractSocket(name string) uint64 { func extractSocket(name string) uint64 {

@ -117,21 +117,21 @@ func findUDPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort ui
}) })
} else if strictness == MATCH_LOOSE { } else if strictness == MATCH_LOOSE {
return findSocket(proto, func(ss socketStatus) bool { return findSocket(proto, func(ss socketStatus) bool {
/* /*
fmt.Println("Match loose") fmt.Println("Match loose")
fmt.Printf("sock dst = %v pkt dst = %v\n", ss.remote.ip, dstAddr) fmt.Printf("sock dst = %v pkt dst = %v\n", ss.remote.ip, dstAddr)
fmt.Printf("sock port = %d pkt port = %d\n", ss.local.port, srcPort) fmt.Printf("sock port = %d pkt port = %d\n", ss.local.port, srcPort)
fmt.Printf("local ip: %v\n source ip: %v\n", ss.local.ip, srcAddr) fmt.Printf("local ip: %v\n source ip: %v\n", ss.local.ip, srcAddr)
*/ */
if (ss.local.port == srcPort && (ss.local.ip.Equal(net.IPv4(0,0,0,0)) && ss.remote.ip.Equal(net.IPv4(0,0,0,0)))) { if ss.local.port == srcPort && (ss.local.ip.Equal(net.IPv4(0, 0, 0, 0)) && ss.remote.ip.Equal(net.IPv4(0, 0, 0, 0))) {
fmt.Printf("Matching for UDP socket bound to *:%d\n",ss.local.port) fmt.Printf("Matching for UDP socket bound to *:%d\n", ss.local.port)
return true return true
} else if (ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr)) { } else if ss.remote.ip.Equal(dstAddr) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) {
return true return true
} }
// Finally, loop through all interfaces if src port matches // Finally, loop through all interfaces if src port matches
if ss.local.port == srcPort { if ss.local.port == srcPort {
ifs, err := net.Interfaces() ifs, err := net.Interfaces()
@ -148,13 +148,13 @@ func findUDPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort ui
for _, addr := range addrs { for _, addr := range addrs {
var ifip net.IP var ifip net.IP
switch x := addr.(type) { switch x := addr.(type) {
case *net.IPNet: case *net.IPNet:
ifip = x.IP ifip = x.IP
case *net.IPAddr: case *net.IPAddr:
ifip = x.IP ifip = x.IP
} }
if ss.local.ip.Equal(ifip) { if ss.local.ip.Equal(ifip) {
fmt.Printf("Matched on UDP socket bound to %v:%d\n",ifip,srcPort) fmt.Printf("Matched on UDP socket bound to %v:%d\n", ifip, srcPort)
return true return true
} }
} }
@ -163,8 +163,8 @@ func findUDPSocketAll(srcAddr net.IP, srcPort uint16, dstAddr net.IP, dstPort ui
return false return false
//return (ss.remote.ip.Equal(dstAddr) || ss.remote.ip.Equal(net.IPv4(0,0,0,0))) && ss.local.port == srcPort && (ss.local.ip.Equal(srcAddr) || ss.local.ip.Equal(net.IPv4(0,0,0,0))) //return (ss.remote.ip.Equal(dstAddr) || ss.remote.ip.Equal(net.IPv4(0,0,0,0))) && ss.local.port == srcPort && (ss.local.ip.Equal(srcAddr) || ss.local.ip.Equal(net.IPv4(0,0,0,0)))
/* /*
return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) || return (ss.remote.ip.Equal(dstAddr) || addrMatchesAny(ss.remote.ip)) && ss.local.port == srcPort && ss.local.ip.Equal(srcAddr) ||
(ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && ss.remote.ip.Equal(srcAddr) */ (ss.local.ip.Equal(dstAddr) || addrMatchesAny(ss.local.ip)) && ss.remote.port == srcPort && ss.remote.ip.Equal(srcAddr) */
}) })
} }
return findSocket(proto, func(ss socketStatus) bool { return findSocket(proto, func(ss socketStatus) bool {
@ -367,11 +367,11 @@ func getSocketLines(proto string) []string {
} }
func addrMatchesAny(addr net.IP) bool { func addrMatchesAny(addr net.IP) bool {
wildcard := net.IP{0,0,0,0} wildcard := net.IP{0, 0, 0, 0}
if addr.To4() == nil { if addr.To4() == nil {
wildcard = net.IP{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} wildcard = net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
} }
return wildcard.Equal(addr) return wildcard.Equal(addr)
} }

Loading…
Cancel
Save