diff --git a/sgfw/policy.go b/sgfw/policy.go index c8873dc..8e1f637 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -175,6 +175,7 @@ func (pp *pendingPkt) print() string { type Policy struct { fw *Firewall path string + sandbox string application string icon string rules RuleList @@ -190,6 +191,32 @@ func (fw *Firewall) PolicyForPath(path string) *Policy { return fw.policyForPath(path) } +func (fw *Firewall) PolicyForPathAndSandbox(path string, sandbox string) *Policy { + fw.lock.Lock() + defer fw.lock.Unlock() + + return fw.policyForPathAndSandbox(path, sandbox) +} + +func (fw *Firewall) policyForPathAndSandbox(path string, sandbox string) *Policy { + policykey := sandbox + "|" + path + if _, ok := fw.policyMap[policykey]; !ok { + p := new(Policy) + p.fw = fw + p.path = path + p.application = path + p.sandbox = sandbox + entry := entryForPath(path) + if entry != nil { + p.application = entry.name + p.icon = entry.icon + } + fw.policyMap[policykey] = p + fw.policies = append(fw.policies, p) + } + return fw.policyMap[policykey] +} + func (fw *Firewall) policyForPath(path string) *Policy { if _, ok := fw.policyMap[path]; !ok { p := new(Policy) @@ -338,7 +365,7 @@ func (p *Policy) removeRule(r *Rule) { func (p *Policy) filterPending(rule *Rule) { remaining := []pendingConnection{} for _, pc := range p.pendingQueue { - if rule.match(pc.src(), pc.dst(), pc.dstPort(), pc.hostname(), pc.proto(), pc.procInfo().UID, pc.procInfo().GID, uidToUser(pc.procInfo().UID), gidToGroup(pc.procInfo().GID), pc.procInfo().Sandbox) { + if rule.match(pc.src(), pc.dst(), pc.dstPort(), pc.hostname(), pc.proto(), pc.procInfo().UID, pc.procInfo().GID, uidToUser(pc.procInfo().UID), gidToGroup(pc.procInfo().GID)) { log.Infof("Adding rule for: %s", rule.getString(FirewallConfig.LogRedact)) log.Noticef("%s > %s", rule.getString(FirewallConfig.LogRedact), pc.print()) if rule.rtype == RULE_ACTION_ALLOW { @@ -475,7 +502,7 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.NFQPacket) { return } */ - policy := fw.PolicyForPath(ppath) + policy := fw.PolicyForPathAndSandbox(ppath,pinfo.Sandbox) //log.Notice("XXX: flunked basicallowpacket; policy = ", policy) policy.processPacket(pkt, pinfo, optstring) } @@ -548,7 +575,7 @@ func getAllProcNetDataLocal() ([]string, error) { return rlines, nil } -func getRealRoot(pathname string, pid int) string { +func GetRealRoot(pathname string, pid int) string { pfname := fmt.Sprintf("/proc/%d/root", pid) lnk, err := os.Readlink(pfname) @@ -611,7 +638,7 @@ func LookupSandboxProc(srcip net.IP, srcp uint16, dstip net.IP, dstp uint16, pro if res != nil { // optstr = "Sandbox: " + OzInitPids[i].Name res.Sandbox = OzInitPids[i].Name - res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid) + res.ExePath = GetRealRoot(res.ExePath, OzInitPids[i].Pid) break } } @@ -710,7 +737,7 @@ func findProcessForPacket(pkt *nfqueue.NFQPacket, reverse bool, strictness int) if res != nil { optstr = "Sandbox: " + OzInitPids[i].Name - res.ExePath = getRealRoot(res.ExePath, OzInitPids[i].Pid) + res.ExePath = GetRealRoot(res.ExePath, OzInitPids[i].Pid) break } } diff --git a/sgfw/prompt.go b/sgfw/prompt.go index a6bdb7b..9793ad1 100644 --- a/sgfw/prompt.go +++ b/sgfw/prompt.go @@ -38,11 +38,11 @@ type prompter struct { func (p *prompter) prompt(policy *Policy) { p.lock.Lock() defer p.lock.Unlock() - _, ok := p.policyMap[policy.path] + _, ok := p.policyMap[policy.sandbox + "|" + policy.path] if ok { return } - p.policyMap[policy.path] = policy + p.policyMap[policy.sandbox + "|" + policy.path] = policy p.policyQueue = append(p.policyQueue, policy) p.cond.Signal() } @@ -268,7 +268,7 @@ func (p *prompter) removePolicy(policy *Policy) { } } p.policyQueue = newQueue - delete(p.policyMap, policy.path) + delete(p.policyMap, policy.sandbox + "|" + policy.path) } var userMap = make(map[int]string) diff --git a/sgfw/rules.go b/sgfw/rules.go index 2aa769b..966da30 100644 --- a/sgfw/rules.go +++ b/sgfw/rules.go @@ -105,7 +105,7 @@ func (r *Rule) AddrString(redact bool) string { type RuleList []*Rule -func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, proto string, uid, gid int, uname, gname string, sandbox string) bool { +func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, proto string, uid, gid int, uname, gname string) bool { if r.proto != proto { return false } @@ -127,6 +127,7 @@ func (r *Rule) match(src net.IP, dst net.IP, dstPort uint16, hostname string, pr return true } if r.hostname != "" { + log.Notice("comparing hostname") if strings.ContainsAny(r.hostname, "*") { regstr := strings.Replace(r.hostname, "*", ".?", -1) match, err := regexp.MatchString(regstr, hostname) @@ -168,25 +169,33 @@ func (rl *RuleList) filter(pkt *nfqueue.NFQPacket, src, dst net.IP, dstPort uint } // sandboxed := strings.HasPrefix(optstr, "SOCKS5|Tor / Sandbox") for _, r := range *rl { - log.Notice("fuck ",r) + nfqproto := "" log.Notice("------------ trying match of src ", src, " against: ", r, " | ", r.saddr, " / optstr = ", optstr, "; pid ", pinfo.Pid, " vs rule pid ", r.pid) log.Notice("r.saddr: ", r.saddr, "src: ", src, "sandboxed ", sandboxed, "optstr: ", optstr) if r.saddr == nil && src != nil && sandboxed { log.Notice("! Skipping comparison against incompatible rule types: rule src = ", r.saddr, " / packet src = ", src) - continue + // continue } else if r.saddr == nil && src == nil && sandboxed { - continue + // continue + // r.match(src, dst, dstPort, hostname, nil, pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID)) + nfqproto = "tcp" } else if r.saddr != nil && !r.saddr.Equal(src) && r.proto != "icmp" { log.Notice("! Skipping comparison of mismatching source ips") continue + } else { + if pkt != nil { + nfqproto = getNFQProto(pkt) + } else { + log.Notice("Weird state.") + } } log.Notice("r.saddr = ", r.saddr, "src = ", src, "\n") if r.pid >= 0 && r.pid != pinfo.Pid { //log.Notice("! Skipping comparison of mismatching PIDs") continue } - if r.match(src, dst, dstPort, hostname, getNFQProto(pkt), pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID), pinfo.Sandbox) { + if r.match(src, dst, dstPort, hostname, nfqproto, pinfo.UID, pinfo.GID, uidToUser(pinfo.UID), gidToGroup(pinfo.GID)) { log.Notice("+ MATCH SUCCEEDED") dstStr := dst.String() if FirewallConfig.LogRedact { @@ -211,11 +220,16 @@ func (rl *RuleList) filter(pkt *nfqueue.NFQPacket, src, dst net.IP, dstPort uint return FILTER_DENY } else if r.rtype == RULE_ACTION_ALLOW { result = FILTER_ALLOW - + return result + /* if r.saddr != nil { return result } - } + */ + } else if r.rtype == RULE_ACTION_ALLOW_TLSONLY { + result = FILTER_ALLOW_TLSONLY + return result + } } else { log.Notice("+ MATCH FAILED") } @@ -425,8 +439,8 @@ func savePolicy(f *os.File, p *Policy) { if !p.hasPersistentRules() { return } - - if !writeLine(f, "["+p.path+"]") { + log.Warningf("p.path: ",p.path) + if !writeLine(f, "["+p.sandbox+"|"+p.path+"]") { return } for _, r := range p.rules { @@ -479,8 +493,9 @@ func (fw *Firewall) loadRules() { } func (fw *Firewall) processPathLine(line string) *Policy { - path := line[1 : len(line)-1] - policy := fw.policyForPath(path) + pathLine := line[1 : len(line)-1] + toks := strings.Split(pathLine, "|") + policy := fw.policyForPathAndSandbox(toks[1],toks[0]) policy.lock.Lock() defer policy.lock.Unlock() policy.rules = nil @@ -489,7 +504,7 @@ func (fw *Firewall) processPathLine(line string) *Policy { func processRuleLine(policy *Policy, line string) { if policy == nil { - log.Warningf("Cannot process rule line without first seeing path line: %s", line) + log.Warningf("Cannot process rule line without first seeing policy key line: %s", line) return } _, err := policy.parseRule(line, true) diff --git a/sgfw/socks_server_chain.go b/sgfw/socks_server_chain.go index f34bb33..537879b 100644 --- a/sgfw/socks_server_chain.go +++ b/sgfw/socks_server_chain.go @@ -36,6 +36,7 @@ type socksChainSession struct { bndAddr *Address optData []byte procInfo procsnitch.ProcInfo + pinfo *procsnitch.Info server *socksChain } @@ -287,13 +288,16 @@ func (c *socksChainSession) filterConnect() (bool, bool) { return false, false } + c.pinfo = pinfo + if optstr == "" { optstr = "Via SOCKS5: " + c.cfg.Name } else { optstr = "[Via SOCKS5: " + c.cfg.Name + "] " + optstr } - policy := c.server.fw.PolicyForPath(pinfo.ExePath) + log.Warningf("Lookup policy for %v %v",pinfo.ExePath,pinfo.Sandbox) + policy := c.server.fw.PolicyForPathAndSandbox(GetRealRoot(pinfo.ExePath,pinfo.Pid),pinfo.Sandbox) hostname, ip, port := c.addressDetails() if ip == nil && hostname == "" { @@ -387,7 +391,11 @@ func (c *socksChainSession) forwardTraffic(tls bool) { err := TLSGuard(c.clientConn, c.upstreamConn, c.req.Addr.addrStr) if err != nil { - log.Error("Dropping traffic due to TLSGuard violation: ", err) + if c.pinfo.Sandbox != "" { + log.Errorf("Dropping traffic from %s (sandbox: %s) to %s due to TLSGuard violation: %v", c.pinfo.ExePath, c.pinfo.Sandbox, c.req.Addr.addrStr, err) + } else { + log.Errorf("Dropping traffic from %s (unsandboxed) to %s due to TLSGuard violation: %v", c.pinfo.ExePath, c.req.Addr.addrStr, err) + } return } else { log.Notice("TLSGuard approved certificate presented for connection to: ", c.req.Addr.addrStr)