Added new SGFW DBus method RunDebugCmd() for retrieving firewall state debugging information.

Eliminated heavy SGFW CPU usage due to long loop condition.
Implemented much more helpful print() method for pendingSocksConnection interface.
testfw program updated to show use of new debugging interface.
Removed lots of noisy debug print statements (and moved many to new debugging facility).
shw_dev
Stephen Watt 7 years ago
parent d7df165517
commit 85d7d60d76

@ -6,6 +6,7 @@ import (
"net" "net"
"path" "path"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/godbus/dbus" "github.com/godbus/dbus"
@ -289,6 +290,19 @@ func (ds *dbusServer) AddRuleAsync(scope uint32, rule, policy, guid string) (boo
return true, nil return true, nil
} }
func (ds *dbusServer) RunDebugCmd(cmd string, params string) (string, *dbus.Error) {
cmd = strings.ToLower(cmd)
result := "Unrecognized debug command: " + cmd
if cmd == "monitorfds" {
result = dumpMonitoredFDs()
} else if cmd == "listpending" {
result = dumpPendingQueues()
}
return result, nil
}
func (ds *dbusServer) AddTestVPC(proto string, srcip string, sport uint16, dstip string, dport uint16, hostname string) (bool, *dbus.Error) { func (ds *dbusServer) AddTestVPC(proto string, srcip string, sport uint16, dstip string, dport uint16, hostname string) (bool, *dbus.Error) {
log.Warningf("AddTestVPC(proto=%s, srcip=%s, sport=%v, dstip=%s, dport=%v, hostname=%s)\n", log.Warningf("AddTestVPC(proto=%s, srcip=%s, sport=%v, dstip=%s, dport=%v, hostname=%s)\n",
proto, srcip, sport, dstip, dport, hostname) proto, srcip, sport, dstip, dport, hostname)

@ -279,7 +279,7 @@ func (fw *Firewall) policyForPath(path string) *Policy {
} }
func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, timestamp time.Time, pinfo *procsnitch.Info, optstr string) { func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, timestamp time.Time, pinfo *procsnitch.Info, optstr string) {
fmt.Println("policy processPacket()") fmt.Println("policy processPacket() running against packet...")
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
@ -554,7 +554,7 @@ func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info
} }
func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket, timestamp time.Time) { func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket, timestamp time.Time) {
fmt.Println("firewall: filterPacket()") // fmt.Println("firewall: filterPacket()")
isudp := pkt.Packet.Layer(layers.LayerTypeUDP) != nil isudp := pkt.Packet.Layer(layers.LayerTypeUDP) != nil
if basicAllowPacket(pkt) { if basicAllowPacket(pkt) {

@ -14,11 +14,19 @@ import (
"github.com/subgraph/fw-daemon/proc-coroner" "github.com/subgraph/fw-daemon/proc-coroner"
) )
var gPrompter *prompter = nil
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)
p.dbusObj = conn.Object("com.subgraph.FirewallPrompt", "/com/subgraph/FirewallPrompt") p.dbusObj = conn.Object("com.subgraph.FirewallPrompt", "/com/subgraph/FirewallPrompt")
p.policyMap = make(map[string]*Policy) p.policyMap = make(map[string]*Policy)
if gPrompter != nil {
fmt.Println("Unexpected: global prompter variable was already set!")
}
gPrompter = p
go p.promptLoop() go p.promptLoop()
return p return p
} }
@ -62,12 +70,14 @@ func (p *prompter) processNextPacket() bool {
pc, empty = p.nextConnection() pc, empty = p.nextConnection()
p.lock.Unlock() p.lock.Unlock()
if pc != nil { if pc != nil {
fmt.Println("GOT NON NIL") fmt.Println("Got next pending connection...")
} }
//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 {
time.Sleep(100 * time.Millisecond)
return false return false
} else if pc == nil { } else if pc == nil {
time.Sleep(100 * time.Millisecond)
continue continue
} else if pc != nil { } else if pc != nil {
break break
@ -80,7 +90,6 @@ func (p *prompter) processNextPacket() bool {
} }
pc.setPrompting(true) pc.setPrompting(true)
fmt.Println("processConnection")
go p.processConnection(pc) go p.processConnection(pc)
return true return true
} }
@ -93,9 +102,48 @@ type PC2FDMapping struct {
prompter *prompter prompter *prompter
} }
func dumpPendingQueues() string {
result := ""
pctotal := 0
if gPrompter == nil {
return "Cannot query pending connections; no prompts have been issued yet!"
}
all_policies := make([]*Policy, 0)
gPrompter.lock.Lock()
defer gPrompter.lock.Unlock()
for _, policy := range gPrompter.policyMap {
all_policies = append(all_policies, policy)
}
result += fmt.Sprintf("Total policies: %d\n", len(all_policies))
for pind, policy := range all_policies {
policy.lock.Lock()
if len(policy.pendingQueue) > 0 {
result += fmt.Sprintf(" Policy %d of %d (%s): #pc = %d\n", pind+1,
len(all_policies), policy.application, len(policy.pendingQueue))
for pcind, pc := range policy.pendingQueue {
result += fmt.Sprintf(" %d: %s\n", pcind+1, pc.print())
pctotal++
}
}
policy.lock.Unlock()
}
result += "-----------------------------------\n"
result = fmt.Sprintf("Pending Queues / total pending connections = %d\n", pctotal) + result
return result
}
var PC2FDMap = map[string]PC2FDMapping{} var PC2FDMap = map[string]PC2FDMapping{}
var PC2FDMapLock = &sync.Mutex{} var PC2FDMapLock = &sync.Mutex{}
var PC2FDMapRunning = false
func monitorPromptFDs(pc pendingConnection) { func monitorPromptFDs(pc pendingConnection) {
guid := pc.getGUID() guid := pc.getGUID()
@ -104,7 +152,7 @@ func monitorPromptFDs(pc pendingConnection) {
fd := pc.procInfo().FD fd := pc.procInfo().FD
prompter := pc.getPrompter() prompter := pc.getPrompter()
fmt.Printf("ADD TO MONITOR: %v | %v / %v / %v\n", pc.policy().application, guid, pid, fd) //fmt.Printf("ADD TO MONITOR: %v | %v / %v / %v\n", pc.policy().application, guid, pid, fd)
if pid == -1 || fd == -1 || prompter == nil { if pid == -1 || fd == -1 || prompter == nil {
log.Warning("Unexpected error condition occurred while adding socket fd to monitor") log.Warning("Unexpected error condition occurred while adding socket fd to monitor")
@ -119,16 +167,28 @@ func monitorPromptFDs(pc pendingConnection) {
return return
} }
func dumpMonitoredFDs() string {
PC2FDMapLock.Lock()
defer PC2FDMapLock.Unlock()
cnt := 1
result := fmt.Sprintf("Monitored FDs: %v total\n", len(PC2FDMap))
for guid, fdmon := range PC2FDMap {
result += fmt.Sprintf("%d: %s -> [inode=%v, fd=%d, fdpath=%s]\n", cnt, guid, fdmon.inode, fdmon.fd, fdmon.fdpath)
cnt++
}
result += "-----------------------------------\n"
return result
}
func monitorPromptFDLoop() { func monitorPromptFDLoop() {
fmt.Println("++++++++++= monitorPromptFDLoop()")
for true { for true {
delete_guids := []string{} delete_guids := []string{}
PC2FDMapLock.Lock() PC2FDMapLock.Lock()
fmt.Println("++++ nentries = ", len(PC2FDMap))
for guid, fdmon := range PC2FDMap { for guid, fdmon := range PC2FDMap {
fmt.Println("ENTRY:", fdmon)
lsb, err := os.Stat(fdmon.fdpath) lsb, err := os.Stat(fdmon.fdpath)
if err != nil { if err != nil {
@ -154,7 +214,10 @@ func monitorPromptFDLoop() {
} }
if len(delete_guids) > 0 {
fmt.Println("guids to delete: ", delete_guids) fmt.Println("guids to delete: ", delete_guids)
}
saved_mappings := []PC2FDMapping{} saved_mappings := []PC2FDMapping{}
for _, guid := range delete_guids { for _, guid := range delete_guids {
saved_mappings = append(saved_mappings, PC2FDMap[guid]) saved_mappings = append(saved_mappings, PC2FDMap[guid])
@ -164,9 +227,10 @@ func monitorPromptFDLoop() {
PC2FDMapLock.Unlock() PC2FDMapLock.Unlock()
for _, mapping := range saved_mappings { for _, mapping := range saved_mappings {
call := mapping.prompter.dbusObj.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, mapping.guid) _ = mapping.prompter.dbusObj.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, mapping.guid)
fmt.Println("DISPOSING CALL = ", call) // fmt.Println("DISPOSING CALL = ", call)
prompter := mapping.prompter prompter := mapping.prompter
found := false
prompter.lock.Lock() prompter.lock.Lock()
@ -177,8 +241,9 @@ func monitorPromptFDLoop() {
for pcind < len(policy.pendingQueue) { for pcind < len(policy.pendingQueue) {
if policy.pendingQueue[pcind].getGUID() == mapping.guid { if policy.pendingQueue[pcind].getGUID() == mapping.guid {
fmt.Println("-------------- found guid to remove") // fmt.Println("-------------- found guid to remove")
policy.pendingQueue = append(policy.pendingQueue[:pcind], policy.pendingQueue[pcind+1:]...) policy.pendingQueue = append(policy.pendingQueue[:pcind], policy.pendingQueue[pcind+1:]...)
found = true
} else { } else {
pcind++ pcind++
} }
@ -188,33 +253,27 @@ func monitorPromptFDLoop() {
policy.lock.Unlock() policy.lock.Unlock()
} }
if !found {
fmt.Println("Warning: FD monitor could not find pending connection to map to removed GUID: %s", mapping.guid)
}
prompter.lock.Unlock() prompter.lock.Unlock()
} }
fmt.Println("++++++++++= monitorPromptFDLoop WAIT")
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
} }
} }
func init() {
go monitorPromptFDLoop()
}
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()
} else {
PC2FDMapLock.Unlock()
}
}
if pc.getPrompter() == nil { if pc.getPrompter() == nil {
pc.setPrompter(p) pc.setPrompter(p)
} }
@ -338,10 +397,10 @@ func (p *prompter) nextConnection() (pendingConnection, bool) {
if len(p.policyQueue) == 0 { if len(p.policyQueue) == 0 {
return nil, true return nil, true
} }
fmt.Println("policy queue len = ", len(p.policyQueue)) //fmt.Println("policy queue len = ", len(p.policyQueue))
for pind < len(p.policyQueue) { for pind < len(p.policyQueue) {
fmt.Printf("policy loop %d of %d\n", pind, len(p.policyQueue)) //fmt.Printf("policy loop %d of %d\n", pind, len(p.policyQueue))
//fmt.Printf("XXX: pind = %v of %v\n", pind, len(p.policyQueue)) //fmt.Printf("XXX: pind = %v of %v\n", pind, len(p.policyQueue))
policy := p.policyQueue[pind] policy := p.policyQueue[pind]
pc, qempty := policy.nextPending() pc, qempty := policy.nextPending()
@ -362,7 +421,11 @@ func (p *prompter) nextConnection() (pendingConnection, bool) {
pendingOther = append(pendingOther, r) pendingOther = append(pendingOther, r)
} }
} }
if len(pendingOnce) > 0 || len(pendingOther) > 0 {
fmt.Printf("# pending once = %d, other = %d, pc = %p / policy = %p\n", len(pendingOnce), len(pendingOther), pc, policy) fmt.Printf("# pending once = %d, other = %d, pc = %p / policy = %p\n", len(pendingOnce), len(pendingOther), pc, policy)
}
policy.rulesPending = pendingOther policy.rulesPending = pendingOther
// One time filters are all applied right here, at once. // One time filters are all applied right here, at once.

@ -161,7 +161,8 @@ func (sc *pendingSocksConnection) setPrompting(val bool) {
} }
func (sc *pendingSocksConnection) print() string { func (sc *pendingSocksConnection) print() string {
return "socks connection" return fmt.Sprintf("SOCKS5 %s {%v:%v -> %v:%v (%s)}",
sc.policy().path, sc.srcIP, sc.sourcePort, sc.destIP, sc.destPort, sc.hname)
} }
func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain { func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain {

@ -7,7 +7,6 @@ import (
"github.com/godbus/dbus" "github.com/godbus/dbus"
) )
const busName = "com.subgraph.FirewallTest" const busName = "com.subgraph.FirewallTest"
const objectPath = "/com/subgraph/FirewallTest" const objectPath = "/com/subgraph/FirewallTest"
const interfaceName = "com.subgraph.FirewallTest" const interfaceName = "com.subgraph.FirewallTest"
@ -58,10 +57,27 @@ func (ds *dbusServer) SGFWTestAlert(accepted int32, guid string, other string) (
return true, nil return true, nil
} }
func CallRunDebugCmd(d *dbusObjectP, cmd string, params string) string {
var dres string
fmt.Printf("> CallRunDebugCmd(cmd = %s, params = %s)\n", cmd, params)
call := d.Call("RunDebugCmd", 0,
cmd, params)
err := call.Store(&dres)
if err != nil {
fmt.Println("Error sending DBus RunDebugCmd() request:", err)
return ""
}
return dres
}
func CallAddTestVPC(d *dbusObjectP, proto string, srcip string, sport uint16, dstip string, dport uint16, hostname string) bool { func CallAddTestVPC(d *dbusObjectP, proto string, srcip string, sport uint16, dstip string, dport uint16, hostname string) bool {
var dres bool var dres bool
fmt.Printf("CallAddTestVPC(proto=%s, srcip=%s, sport=%u, dstip=%s, dport=%u, hostname=%s)\n", fmt.Printf("> CallAddTestVPC(proto=%s, srcip=%s, sport=%u, dstip=%s, dport=%u, hostname=%s)\n",
proto, srcip, sport, dstip, dport, hostname) proto, srcip, sport, dstip, dport, hostname)
call := d.Call("AddTestVPC", 0, call := d.Call("AddTestVPC", 0,

@ -8,7 +8,6 @@ import (
var dbuso *dbusObjectP var dbuso *dbusObjectP
func main() { func main() {
fmt.Println("Starting up test units...") fmt.Println("Starting up test units...")
@ -26,11 +25,26 @@ func main() {
res := CallAddTestVPC(dbuso, "udp", "10.0.0.1", 61921, "8.8.8.8", 53, "dnsthing.google.com") res := CallAddTestVPC(dbuso, "udp", "10.0.0.1", 61921, "8.8.8.8", 53, "dnsthing.google.com")
fmt.Println("res =", res) fmt.Println("res =", res)
fmt.Println("Looping until interrupted...")
fmt.Println("Waiting until interrupted...")
for true { for true {
time.Sleep(1 * time.Second) result := CallRunDebugCmd(dbuso, "monitorfds", "")
if result == "" {
fmt.Println("Error: could not read monitored FDs information from SGFW.")
} else {
fmt.Println(result)
}
result = CallRunDebugCmd(dbuso, "listpending", "")
if result == "" {
fmt.Println("Error: could not read pending queue(s) information from SGFW.")
} else {
fmt.Println(result)
}
time.Sleep(5 * time.Second)
} }
} }

Loading…
Cancel
Save