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
} }

@ -48,6 +48,7 @@ type ruleColumns struct {
Uname string Uname string
Gname string Gname string
Origin string Origin string
Timestamp string
IsSocks bool IsSocks bool
ForceTLS bool ForceTLS bool
Scope int Scope int
@ -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