Added connection timestamps to firewall prompting.

Disabled old synchronous RequestPrompt Dbus method in fw-prompt.
fw-prompt GUI now (as originally) remains above other windows when there are pending decisions.
Fixed improper traversal of pending connections in fw-prompt GUI.
Consolidated redundant code blocks in fw-prompt GUI.
shw_dev
Stephen Watt 7 years ago
parent 0bda150abc
commit ff8be65566

@ -1,5 +1,5 @@
fw-daemon: fw-daemon:
pc.socks() an getOptString() return overlapping information pc.socks() and getOptString() return overlapping information
remove all stale references to SANDBOX: rules/policyForPathAndSandbox() remove all stale references to SANDBOX: rules/policyForPathAndSandbox()
@ -7,13 +7,6 @@ fw-daemon:
fw-prompt: fw-prompt:
scope returned by new rules is bad (always set to process) scope returned by new rules is bad (always set to process)
prompter should have a timestamp field
Iteration through fw-prompt choices can't brute force by index #
This function needs to be updated because it no longer works:
func toggleHover() { mainWin.SetKeepAbove(len(decisionWaiters) > 0) }
Each duplicate prompt needs to be expandable into individual items Each duplicate prompt needs to be expandable into individual items

@ -52,10 +52,10 @@ func newDbusServer() (*dbusServer, error) {
return ds, nil return ds, nil
} }
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, timestamp string, 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, int(action)) decision := addRequest(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, timestamp, 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 {
@ -64,12 +64,12 @@ func (ds *dbusServer) RequestPrompt(guid, application, icon, path, address strin
log.Print("Decision returned: ", decision.Rule) log.Print("Decision returned: ", decision.Rule)
decision.Cond.L.Unlock() decision.Cond.L.Unlock()
return int32(decision.Scope), decision.Rule, nil return int32(decision.Scope), decision.Rule, nil
} }*/
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, timestamp string, 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, int(action)) addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, timestamp, is_socks, optstring, sandbox, int(action))
return true, nil return true, nil
} }

@ -34,23 +34,24 @@ type decisionWaiter struct {
} }
type ruleColumns struct { type ruleColumns struct {
nrefs int nrefs int
Path string Path string
GUID string GUID string
Icon string Icon string
Proto string Proto string
Pid int Pid int
Target string Target string
Hostname string Hostname string
Port int Port int
UID int UID int
GID int GID int
Uname string Uname string
Gname string Gname string
Origin string Origin string
IsSocks bool Timestamp string
ForceTLS bool IsSocks bool
Scope int ForceTLS bool
Scope int
} }
var dbuso *dbusObject var dbuso *dbusObject
@ -70,6 +71,7 @@ var btnApprove, btnDeny, btnIgnore *gtk.Button
var chkTLS, chkUser, chkGroup *gtk.CheckButton var chkTLS, chkUser, chkGroup *gtk.CheckButton
func dumpDecisions() { func dumpDecisions() {
return
fmt.Println("XXX Total of decisions pending: ", len(decisionWaiters)) fmt.Println("XXX Total of decisions pending: ", len(decisionWaiters))
for i := 0; i < len(decisionWaiters); i++ { for i := 0; i < len(decisionWaiters); i++ {
fmt.Printf("XXX %d ready = %v, rule = %v\n", i+1, decisionWaiters[i].Ready, decisionWaiters[i].Rule) fmt.Printf("XXX %d ready = %v, rule = %v\n", i+1, decisionWaiters[i].Ready, decisionWaiters[i].Rule)
@ -77,6 +79,7 @@ func dumpDecisions() {
} }
func addDecision() *decisionWaiter { func addDecision() *decisionWaiter {
return nil
decision := decisionWaiter{Lock: &sync.Mutex{}, Ready: false, Scope: int(sgfw.APPLY_ONCE), Rule: ""} decision := decisionWaiter{Lock: &sync.Mutex{}, Ready: false, Scope: int(sgfw.APPLY_ONCE), Rule: ""}
decision.Cond = sync.NewCond(decision.Lock) decision.Cond = sync.NewCond(decision.Lock)
decisionWaiters = append(decisionWaiters, &decision) decisionWaiters = append(decisionWaiters, &decision)
@ -315,7 +318,7 @@ 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, glib.TYPE_STRING, 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_INT, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_STRING, glib.TYPE_INT} glib.TYPE_STRING, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_INT, glib.TYPE_STRING, 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 {
@ -331,7 +334,7 @@ func removeRequest(listStore *gtk.ListStore, guid string) {
defer globalPromptLock.Unlock() defer globalPromptLock.Unlock()
/* XXX: This is horrible. Figure out how to do this properly. */ /* XXX: This is horrible. Figure out how to do this properly. */
for ridx := 0; ridx < 2000; ridx++ { for ridx := 0; ridx < globalLS.IterNChildren(nil); ridx++ {
rule, _, err := getRuleByIdx(ridx) rule, _, err := getRuleByIdx(ridx)
if err != nil { if err != nil {
@ -357,7 +360,7 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
globalPromptLock.Lock() globalPromptLock.Lock()
defer globalPromptLock.Unlock() defer globalPromptLock.Unlock()
for ridx := 0; ridx < 2000; ridx++ { for ridx := 0; ridx < globalLS.IterNChildren(nil); ridx++ {
/* XXX: This is horrible. Figure out how to do this properly. */ /* XXX: This is horrible. Figure out how to do this properly. */
rule, iter, err := getRuleByIdx(ridx) rule, iter, err := getRuleByIdx(ridx)
@ -385,98 +388,14 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
} }
func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, 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 { origin, timestamp string, is_socks bool, optstring string, sandbox string, action int) bool {
if listStore == nil { addRequest(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, timestamp, is_socks,
listStore = globalLS optstring, sandbox, action)
waitTimes := []int{1, 2, 5, 10}
if listStore == nil {
log.Println("SGFW prompter was not ready to receive firewall request... waiting")
for _, wtime := range waitTimes {
time.Sleep(time.Duration(wtime) * time.Second)
listStore = globalLS
if listStore != nil {
break
}
log.Println("SGFW prompter is still waiting...")
}
}
}
if listStore == nil {
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, action) {
fmt.Println("REQUEST WAS DUPLICATE")
return false
} else {
fmt.Println("NOT DUPLICATE")
}
globalPromptLock.Lock()
iter := listStore.Append()
if is_socks {
if (optstring != "") && (strings.Index(optstring, "SOCKS") == -1) {
optstring = "SOCKS5 / " + optstring
} else if optstring == "" {
optstring = "SOCKS5"
}
}
colVals := make([]interface{}, 15)
colVals[0] = 1
colVals[1] = guid
colVals[2] = path
colVals[3] = icon
colVals[4] = proto
colVals[5] = pid
if ipaddr == "" {
colVals[6] = "---"
} else {
colVals[6] = ipaddr
}
colVals[7] = hostname
colVals[8] = port
colVals[9] = uid
colVals[10] = gid
colVals[11] = origin
colVals[12] = 0
if is_socks {
colVals[12] = 1
}
colVals[13] = optstring
colVals[14] = action
colNums := make([]int, len(colVals))
for n := 0; n < len(colVals); n++ {
colNums[n] = n
}
err := listStore.Set(iter, colNums, colVals)
globalPromptLock.Unlock()
if err != nil {
log.Fatal("Unable to add row:", err)
}
toggleHover()
return true return true
} }
func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, 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 { origin, timestamp 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}
@ -506,7 +425,9 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox, action) { 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()
globalPromptLock.Lock()
toggleHover() toggleHover()
globalPromptLock.Unlock()
return decision return decision
} else { } else {
fmt.Println("NOT DUPLICATE") fmt.Println("NOT DUPLICATE")
@ -523,7 +444,7 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
} }
} }
colVals := make([]interface{}, 15) colVals := make([]interface{}, 16)
colVals[0] = 1 colVals[0] = 1
colVals[1] = guid colVals[1] = guid
colVals[2] = path colVals[2] = path
@ -542,14 +463,15 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
colVals[9] = uid colVals[9] = uid
colVals[10] = gid colVals[10] = gid
colVals[11] = origin colVals[11] = origin
colVals[12] = 0 colVals[12] = timestamp
colVals[13] = 0
if is_socks { if is_socks {
colVals[12] = 1 colVals[13] = 1
} }
colVals[13] = optstring colVals[14] = optstring
colVals[14] = action colVals[15] = action
colNums := make([]int, len(colVals)) colNums := make([]int, len(colVals))
@ -558,7 +480,6 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
} }
err := listStore.Set(iter, colNums, colVals) err := listStore.Set(iter, colNums, colVals)
globalPromptLock.Unlock()
if err != nil { if err != nil {
log.Fatal("Unable to add row:", err) log.Fatal("Unable to add row:", err)
@ -567,6 +488,7 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
decision := addDecision() decision := addDecision()
dumpDecisions() dumpDecisions()
toggleHover() toggleHover()
globalPromptLock.Unlock()
return decision return decision
} }
@ -682,14 +604,17 @@ func makeDecision(idx int, rule string, scope int) error {
return nil return nil
} }
/* Do we need to hold the lock while this is called? Stay safe... */
func toggleHover() { func toggleHover() {
mainWin.SetKeepAbove(len(decisionWaiters) > 0) nitems := globalLS.IterNChildren(nil)
mainWin.SetKeepAbove(nitems > 0)
} }
func toggleValidRuleState() { func toggleValidRuleState() {
ok := true ok := true
// Unfortunately, this can cause deadlock since it's a part ofi the item removal cascade // Unfortunately, this can cause deadlock since it's a part of the item removal cascade
// globalPromptLock.Lock() // globalPromptLock.Lock()
// defer globalPromptLock.Unlock() // defer globalPromptLock.Unlock()
@ -912,8 +837,13 @@ func getRuleByIdx(idx int) (ruleColumns, *gtk.TreeIter, error) {
return rule, nil, err return rule, nil, err
} }
rule.Timestamp, err = lsGetStr(globalLS, iter, 12)
if err != nil {
return rule, nil, err
}
rule.IsSocks = false rule.IsSocks = false
is_socks, err := lsGetInt(globalLS, iter, 12) is_socks, err := lsGetInt(globalLS, iter, 13)
if err != nil { if err != nil {
return rule, nil, err return rule, nil, err
} }
@ -922,7 +852,7 @@ func getRuleByIdx(idx int) (ruleColumns, *gtk.TreeIter, error) {
rule.IsSocks = true rule.IsSocks = true
} }
rule.Scope, err = lsGetInt(globalLS, iter, 14) rule.Scope, err = lsGetInt(globalLS, iter, 15)
if err != nil { if err != nil {
return rule, nil, err return rule, nil, err
} }
@ -965,7 +895,7 @@ func addPendingPrompts(rules []string) {
for _, rule := range rules { for _, rule := range rules {
fields := strings.Split(rule, "|") fields := strings.Split(rule, "|")
if len(fields) != 18 { if len(fields) != 19 {
log.Printf("Got saved prompt message with strange data: \"%s\"", rule) log.Printf("Got saved prompt message with strange data: \"%s\"", rule)
continue continue
} }
@ -1011,15 +941,16 @@ func addPendingPrompts(rules []string) {
continue continue
} }
optstring := fields[16] timestamp := fields[16]
optstring := fields[17]
action, err := strconv.Atoi(fields[17]) action, err := strconv.Atoi(fields[18])
if err != nil { if err != nil {
log.Println("Error converting action in pending prompt message to integer:", err) log.Println("Error converting action in pending prompt message to integer:", err)
continue continue
} }
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox, action) addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, timestamp, is_socks, optstring, sandbox, action)
} }
} }
@ -1255,14 +1186,15 @@ func main() {
tv.AppendColumn(createColumn("UID", 9)) tv.AppendColumn(createColumn("UID", 9))
tv.AppendColumn(createColumn("GID", 10)) tv.AppendColumn(createColumn("GID", 10))
tv.AppendColumn(createColumn("Origin", 11)) tv.AppendColumn(createColumn("Origin", 11))
tv.AppendColumn(createColumn("Timestamp", 12))
scol := createColumn("Is SOCKS", 12) scol := createColumn("Is SOCKS", 13)
scol.SetVisible(false) scol.SetVisible(false)
tv.AppendColumn(scol) tv.AppendColumn(scol)
tv.AppendColumn(createColumn("Details", 13)) tv.AppendColumn(createColumn("Details", 14))
acol := createColumn("Scope", 14) acol := createColumn("Scope", 15)
acol.SetVisible(false) acol.SetVisible(false)
tv.AppendColumn(acol) tv.AppendColumn(acol)

@ -241,6 +241,7 @@ 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.getTimestamp() + "|"
pstr += pc.getOptString() + "|" pstr += pc.getOptString() + "|"
pstr += strconv.FormatUint(uint64(FirewallConfig.DefaultActionID), 10) pstr += strconv.FormatUint(uint64(FirewallConfig.DefaultActionID), 10)
pending_data = append(pending_data, pstr) pending_data = append(pending_data, pstr)

@ -13,6 +13,7 @@ import (
"net" "net"
"os" "os"
"syscall" "syscall"
"time"
"unsafe" "unsafe"
) )
@ -53,6 +54,7 @@ type pendingConnection interface {
setPrompter(*prompter) setPrompter(*prompter)
getPrompter() *prompter getPrompter() *prompter
getGUID() string getGUID() string
getTimestamp() string
print() string print() string
} }
@ -65,6 +67,7 @@ type pendingPkt struct {
prompting bool prompting bool
prompter *prompter prompter *prompter
guid string guid string
timestamp time.Time
} }
/* Not a *REAL* GUID */ /* Not a *REAL* GUID */
@ -97,6 +100,10 @@ func (pp *pendingPkt) sandbox() string {
return pp.pinfo.Sandbox return pp.pinfo.Sandbox
} }
func (pc *pendingPkt) getTimestamp() string {
return pc.timestamp.Format("15:04:05.00")
}
func (pp *pendingPkt) socks() bool { func (pp *pendingPkt) socks() bool {
return false return false
} }
@ -281,13 +288,9 @@ func (fw *Firewall) policyForPath(path string) *Policy {
return fw.policyMap[path] return fw.policyMap[path]
} }
func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, 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()")
/* hbytes, err := pkt.GetHWAddr()
if err != nil {
log.Notice("Failed to get HW address underlying packet: ", err)
} else { log.Notice("got hwaddr: ", hbytes) } */
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
dstb := pkt.Packet.NetworkLayer().NetworkFlow().Dst().Raw() dstb := pkt.Packet.NetworkLayer().NetworkFlow().Dst().Raw()
@ -320,7 +323,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, prompter: nil, prompting: false}) p.processPromptResult(&pendingPkt{pol: p, name: name, pkt: pkt, pinfo: pinfo, optstring: optstr, prompter: nil, timestamp: timestamp, prompting: false})
default: default:
log.Warningf("Unexpected filter result: %d", result) log.Warningf("Unexpected filter result: %d", result)
} }
@ -499,7 +502,7 @@ func printPacket(pkt *nfqueue.NFQPacket, hostname string, pinfo *procsnitch.Info
return fmt.Sprintf("%s %s %s:%d -> %s:%d", pinfo.ExePath, proto, SrcIp, SrcPort, name, DstPort) return fmt.Sprintf("%s %s %s:%d -> %s:%d", pinfo.ExePath, proto, SrcIp, SrcPort, name, DstPort)
} }
func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) { 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
@ -578,7 +581,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) {
*/ */
policy := fw.PolicyForPathAndSandbox(ppath, pinfo.Sandbox) policy := fw.PolicyForPathAndSandbox(ppath, pinfo.Sandbox)
//log.Notice("XXX: flunked basicallowpacket; policy = ", policy) //log.Notice("XXX: flunked basicallowpacket; policy = ", policy)
policy.processPacket(pkt, pinfo, optstring) policy.processPacket(pkt, timestamp, pinfo, optstring)
} }
func readFileDirect(filename string) ([]byte, error) { func readFileDirect(filename string) ([]byte, error) {

@ -248,6 +248,7 @@ func (p *prompter) processConnection(pc pendingConnection) {
int32(pc.procInfo().Pid), int32(pc.procInfo().Pid),
pc.sandbox(), pc.sandbox(),
pc.socks(), pc.socks(),
pc.getTimestamp(),
pc.getOptString(), pc.getOptString(),
FirewallConfig.PromptExpanded, FirewallConfig.PromptExpanded,
FirewallConfig.PromptExpert, FirewallConfig.PromptExpert,

@ -1,16 +1,16 @@
package sgfw package sgfw
import ( import (
"bufio"
"encoding/json"
"fmt"
"os" "os"
"os/signal" "os/signal"
"regexp" "regexp"
"strings"
"sync" "sync"
"syscall" "syscall"
// "time" "time"
"bufio"
"encoding/json"
"fmt"
"strings"
"github.com/op/go-logging" "github.com/op/go-logging"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
@ -110,6 +110,8 @@ func (fw *Firewall) runFilter() {
go func() { go func() {
for p := range ps { for p := range ps {
timestamp := time.Now()
if fw.isEnabled() { if fw.isEnabled() {
ipLayer := p.Packet.Layer(layers.LayerTypeIPv4) ipLayer := p.Packet.Layer(layers.LayerTypeIPv4)
if ipLayer == nil { if ipLayer == nil {
@ -127,7 +129,7 @@ func (fw *Firewall) runFilter() {
} }
fw.filterPacket(p) fw.filterPacket(p, timestamp)
} else { } else {
p.Accept() p.Accept()
} }

@ -59,6 +59,7 @@ type pendingSocksConnection struct {
prompter *prompter prompter *prompter
guid string guid string
optstr string optstr string
timestamp time.Time
} }
func (sc *pendingSocksConnection) sandbox() string { func (sc *pendingSocksConnection) sandbox() string {
@ -116,17 +117,31 @@ func (sc *pendingSocksConnection) deliverVerdict(v int) {
} }
} }
func (sc *pendingSocksConnection) accept() { sc.deliverVerdict(socksVerdictAccept) } func (sc *pendingSocksConnection) accept() {
sc.deliverVerdict(socksVerdictAccept)
}
// need to generalize special accept // need to generalize special accept
func (sc *pendingSocksConnection) acceptTLSOnly() { sc.deliverVerdict(socksVerdictAcceptTLSOnly) } func (sc *pendingSocksConnection) acceptTLSOnly() {
sc.deliverVerdict(socksVerdictAcceptTLSOnly)
}
func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) } func (sc *pendingSocksConnection) drop() {
sc.deliverVerdict(socksVerdictDrop)
}
func (sc *pendingSocksConnection) setPrompter(val *prompter) {
sc.prompter = val
}
func (sc *pendingSocksConnection) setPrompter(val *prompter) { sc.prompter = val } func (sc *pendingSocksConnection) getPrompter() *prompter {
return sc.prompter
}
func (sc *pendingSocksConnection) getPrompter() *prompter { return sc.prompter } func (sc *pendingSocksConnection) getTimestamp() string {
return sc.timestamp.Format("15:04:05.00")
}
func (sc *pendingSocksConnection) getGUID() string { func (sc *pendingSocksConnection) getGUID() string {
if sc.guid == "" { if sc.guid == "" {
@ -136,11 +151,17 @@ func (sc *pendingSocksConnection) getGUID() string {
return sc.guid return sc.guid
} }
func (sc *pendingSocksConnection) getPrompting() bool { return sc.prompting } func (sc *pendingSocksConnection) getPrompting() bool {
return sc.prompting
}
func (sc *pendingSocksConnection) setPrompting(val bool) { sc.prompting = val } 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 {
chain := socksChain{ chain := socksChain{
@ -163,10 +184,11 @@ func (s *socksChain) start() {
} }
s.wg.Add(1) s.wg.Add(1)
go s.socksAcceptLoop() ts := time.Now()
go s.socksAcceptLoop(ts)
} }
func (s *socksChain) socksAcceptLoop() error { func (s *socksChain) socksAcceptLoop(timestamp time.Time) error {
defer s.wg.Done() defer s.wg.Done()
defer s.listener.Close() defer s.listener.Close()
@ -180,11 +202,11 @@ func (s *socksChain) socksAcceptLoop() error {
continue continue
} }
session := &socksChainSession{cfg: s.cfg, clientConn: conn, procInfo: s.procInfo, server: s} session := &socksChainSession{cfg: s.cfg, clientConn: conn, procInfo: s.procInfo, server: s}
go session.sessionWorker() go session.sessionWorker(timestamp)
} }
} }
func (c *socksChainSession) sessionWorker() { func (c *socksChainSession) sessionWorker(timestamp time.Time) {
defer c.clientConn.Close() defer c.clientConn.Close()
clientAddr := c.clientConn.RemoteAddr() clientAddr := c.clientConn.RemoteAddr()
@ -214,7 +236,7 @@ func (c *socksChainSession) sessionWorker() {
c.req.ReplyAddr(ReplySucceeded, c.bndAddr) c.req.ReplyAddr(ReplySucceeded, c.bndAddr)
} }
case CommandConnect: case CommandConnect:
verdict, tls := c.filterConnect() verdict, tls := c.filterConnect(timestamp)
if !verdict { if !verdict {
c.req.Reply(ReplyConnectionRefused) c.req.Reply(ReplyConnectionRefused)
@ -295,7 +317,7 @@ func findProxyEndpoint(pdata []string, conn net.Conn) (*procsnitch.Info, string)
return nil, "" return nil, ""
} }
func (c *socksChainSession) filterConnect() (bool, bool) { func (c *socksChainSession) filterConnect(timestamp time.Time) (bool, bool) {
// return filter verdict, tlsguard // return filter verdict, tlsguard
allProxies, err := ListProxies() allProxies, err := ListProxies()
@ -383,6 +405,7 @@ func (c *socksChainSession) filterConnect() (bool, bool) {
prompting: false, prompting: false,
prompter: nil, prompter: nil,
optstr: optstr, optstr: optstr,
timestamp: timestamp,
} }
policy.processPromptResult(pending) policy.processPromptResult(pending)
v := <-pending.verdict v := <-pending.verdict

@ -2,6 +2,7 @@ package sgfw
import ( import (
"crypto/x509" "crypto/x509"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -62,6 +63,20 @@ type connReader struct {
err error err error
} }
var cipherSuiteMap map[uint16]string = map[uint16]string{
0x0000: "TLS_NULL_WITH_NULL_NULL",
0x0030: "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
}
func getCipherSuiteName(value uint) string {
val, ok := cipherSuiteMap[uint16(value)]
if !ok {
return "UNKNOWN"
}
return val
}
func connectionReader(conn net.Conn, is_client bool, c chan connReader, done chan bool) { func connectionReader(conn net.Conn, is_client bool, c chan connReader, done chan bool) {
var ret_error error = nil var ret_error error = nil
buffered := []byte{} buffered := []byte{}
@ -226,8 +241,8 @@ select_loop:
other.Write(cr.data) other.Write(cr.data)
continue continue
} else if cr.client { } else if cr.client {
other.Write(cr.data) // other.Write(cr.data)
continue // continue
} else if cr.rtype != SSL3_RT_HANDSHAKE { } else if cr.rtype != SSL3_RT_HANDSHAKE {
return errors.New(fmt.Sprintf("Expected TLS server handshake byte was not received [%#x vs 0x16]", cr.rtype)) return errors.New(fmt.Sprintf("Expected TLS server handshake byte was not received [%#x vs 0x16]", cr.rtype))
} }
@ -236,8 +251,8 @@ select_loop:
return errors.New(fmt.Sprintf("TLSGuard dropping connection with unknown content type: %#x", cr.rtype)) return errors.New(fmt.Sprintf("TLSGuard dropping connection with unknown content type: %#x", cr.rtype))
} }
serverMsg := cr.data[5:] handshakeMsg := cr.data[5:]
s := uint(serverMsg[0]) s := uint(handshakeMsg[0])
fmt.Printf("s = %#x\n", s) fmt.Printf("s = %#x\n", s)
if cr.client && s != uint(client_expected) { if cr.client && s != uint(client_expected) {
@ -246,6 +261,31 @@ select_loop:
return errors.New(fmt.Sprintf("Server sent handshake type %#x but expected %#x", s, server_expected)) return errors.New(fmt.Sprintf("Server sent handshake type %#x but expected %#x", s, server_expected))
} }
if cr.client {
if s == SSL3_MT_CLIENT_HELLO {
fmt.Println("CLIENT HELLO")
hello_offset := 4
// 2 byte protocol version
fmt.Println("CLIENT HELLO VERSION = ", handshakeMsg[hello_offset:hello_offset+2])
hello_offset += 2
// 4 byte Random/GMT time
fmt.Println("CLIENT HELLO GMT = ", handshakeMsg[hello_offset:hello_offset+4])
hello_offset += 4
// 28 bytes Random/random_bytes
hello_offset += 28
// 1 byte (32-bit session ID)
fmt.Println("CLIENT HELLO SESSION ID = ", handshakeMsg[hello_offset:hello_offset+1])
hello_offset++
// 2 byte cipher suite array
cs := binary.BigEndian.Uint16(handshakeMsg[hello_offset : hello_offset+2])
fmt.Printf("cs = %v / %#v\n", cs, cs)
fmt.Printf("CLIENT HELLO CIPHERSUITE: %v (%s)\n", handshakeMsg[hello_offset:hello_offset+2], getCipherSuiteName(uint(cs)))
}
other.Write(cr.data)
continue
}
if !cr.client && s == SSL3_MT_HELLO_REQUEST { if !cr.client && s == SSL3_MT_HELLO_REQUEST {
fmt.Println("Server sent hello request") fmt.Println("Server sent hello request")
continue continue
@ -256,16 +296,16 @@ select_loop:
} }
// Message len, 3 bytes // Message len, 3 bytes
serverMessageLen := serverMsg[1:4] handshakeMessageLen := handshakeMsg[1:4]
serverMessageLenInt := int(int(serverMessageLen[0])<<16 | int(serverMessageLen[1])<<8 | int(serverMessageLen[2])) handshakeMessageLenInt := int(int(handshakeMessageLen[0])<<16 | int(handshakeMessageLen[1])<<8 | int(handshakeMessageLen[2]))
if s == SSL3_MT_CERTIFICATE { if s == SSL3_MT_CERTIFICATE {
fmt.Println("HMM") fmt.Println("HMM")
// fmt.Printf("chunk len = %v, serverMsgLen = %v, slint = %v\n", len(chunk), len(serverMsg), serverMessageLenInt) // fmt.Printf("chunk len = %v, handshakeMsgLen = %v, slint = %v\n", len(chunk), len(handshakeMsg), handshakeMessageLenInt)
if len(serverMsg) < serverMessageLenInt { if len(handshakeMsg) < handshakeMessageLenInt {
return errors.New(fmt.Sprintf("len(serverMsg) %v < serverMessageLenInt %v!\n", len(serverMsg), serverMessageLenInt)) return errors.New(fmt.Sprintf("len(handshakeMsg) %v < handshakeMessageLenInt %v!\n", len(handshakeMsg), handshakeMessageLenInt))
} }
serverHelloBody := serverMsg[4 : 4+serverMessageLenInt] serverHelloBody := handshakeMsg[4 : 4+handshakeMessageLenInt]
certChainLen := int(int(serverHelloBody[0])<<16 | int(serverHelloBody[1])<<8 | int(serverHelloBody[2])) certChainLen := int(int(serverHelloBody[0])<<16 | int(serverHelloBody[1])<<8 | int(serverHelloBody[2]))
remaining := certChainLen remaining := certChainLen
pos := serverHelloBody[3:certChainLen] pos := serverHelloBody[3:certChainLen]

Loading…
Cancel
Save