From 30a21eaa570b03e9bae5e372c5c3b919a917c21a Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Mon, 25 Jan 2016 18:24:23 +0000 Subject: [PATCH] Moved /proc parsing code into a new package --- main.go | 2 ++ policy.go | 19 +++++++++-------- proc.go => proc/proc.go | 37 +++++++++++++++++++++++++-------- proc_pid.go => proc/proc_pid.go | 31 ++++++++++++++------------- prompt.go | 4 ++-- rules.go | 5 +++-- 6 files changed, 61 insertions(+), 37 deletions(-) rename proc.go => proc/proc.go (92%) rename proc_pid.go => proc/proc_pid.go (78%) diff --git a/main.go b/main.go index 403a147..dd6f3d6 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "sync" "syscall" "unsafe" + "github.com/subgraph/fw-daemon/proc" ) var log = logging.MustGetLogger("sgfw") @@ -71,6 +72,7 @@ func (fw *Firewall) runFilter() { } func main() { + proc.SetLogger(log) if os.Geteuid() != 0 { log.Error("Must be run as root") diff --git a/policy.go b/policy.go index d9b829b..c523fd5 100644 --- a/policy.go +++ b/policy.go @@ -5,13 +5,14 @@ import ( "sync" "github.com/subgraph/fw-daemon/nfqueue" + "github.com/subgraph/fw-daemon/proc" ) type pendingPkt struct { policy *Policy hostname string pkt *nfqueue.Packet - proc *ProcInfo + pinfo *proc.ProcInfo } type Policy struct { @@ -42,12 +43,12 @@ func (fw *Firewall) policyForPath(path string) *Policy { return fw.policyMap[path] } -func (p *Policy) processPacket(pkt *nfqueue.Packet, proc *ProcInfo) { +func (p *Policy) processPacket(pkt *nfqueue.Packet, pinfo *proc.ProcInfo) { p.lock.Lock() defer p.lock.Unlock() name := p.fw.dns.Lookup(pkt.Dst) log.Info("Lookup(%s): %s", pkt.Dst.String(), name) - result := p.rules.filter(pkt, proc, name) + result := p.rules.filter(pkt, pinfo, name) switch result { case FILTER_DENY: pkt.Mark = 1 @@ -55,7 +56,7 @@ func (p *Policy) processPacket(pkt *nfqueue.Packet, proc *ProcInfo) { case FILTER_ALLOW: pkt.Accept() case FILTER_PROMPT: - p.processPromptResult(&pendingPkt{policy: p, hostname: name, pkt: pkt, proc: proc}) + p.processPromptResult(&pendingPkt{policy: p, hostname: name, pkt: pkt, pinfo: pinfo}) default: log.Warning("Unexpected filter result: %d", result) } @@ -162,21 +163,21 @@ func (fw *Firewall) filterPacket(pkt *nfqueue.Packet) { fw.dns.processDNS(pkt) return } - proc := findProcessForPacket(pkt) - if proc == nil { + pinfo := proc.FindProcessForPacket(pkt) + if pinfo == nil { log.Warning("No proc found for %s", printPacket(pkt, fw.dns.Lookup(pkt.Dst))) pkt.Accept() return } - log.Debug("filterPacket [%s] %s", proc.exePath, printPacket(pkt, fw.dns.Lookup(pkt.Dst))) + log.Debug("filterPacket [%s] %s", pinfo.ExePath, printPacket(pkt, fw.dns.Lookup(pkt.Dst))) if basicAllowPacket(pkt) { pkt.Accept() return } fw.lock.Lock() - policy := fw.policyForPath(proc.exePath) + policy := fw.policyForPath(pinfo.ExePath) fw.lock.Unlock() - policy.processPacket(pkt, proc) + policy.processPacket(pkt, pinfo) } func basicAllowPacket(pkt *nfqueue.Packet) bool { diff --git a/proc.go b/proc/proc.go similarity index 92% rename from proc.go rename to proc/proc.go index 4ae0497..503d01f 100644 --- a/proc.go +++ b/proc/proc.go @@ -1,4 +1,4 @@ -package main +package proc import ( "encoding/hex" @@ -10,10 +10,15 @@ import ( "path/filepath" "strconv" "strings" - + "github.com/subgraph/fw-daemon/Godeps/_workspace/src/github.com/op/go-logging" "github.com/subgraph/fw-daemon/nfqueue" ) +var log = logging.MustGetLogger("proc") +func SetLogger(logger *logging.Logger) { + log = logger +} + type socketAddr struct { ip net.IP port uint16 @@ -47,7 +52,7 @@ func (ci *ConnectionInfo) String() string { return fmt.Sprintf("%v %s %s", ci.proc, ci.local, ci.remote) } -func findProcessForPacket(pkt *nfqueue.Packet) *ProcInfo { +func FindProcessForPacket(pkt *nfqueue.Packet) *ProcInfo { ss := getSocketForPacket(pkt) if ss == nil { return nil @@ -79,10 +84,10 @@ func findProcessForSocket(ss *socketStatus) *ProcInfo { } finfo.Sys() return &ProcInfo{ - pid: ss.pid, - uid: ss.uid, - exePath: exePath, - cmdLine: string(bs), + Pid: ss.pid, + Uid: ss.uid, + ExePath: exePath, + CmdLine: string(bs), } } @@ -153,6 +158,20 @@ func (ss *socketStatus) parseLine(line string) error { return nil } +func printPacket(pkt *nfqueue.Packet) string { + proto := func() string { + switch pkt.Protocol { + case nfqueue.TCP: + return "TCP" + case nfqueue.UDP: + return "UDP" + default: + return "???" + } + }() + return fmt.Sprintf("(%s %s:%d --> %s:%d)", proto, pkt.Src, pkt.SrcPort, pkt.Dst.String(), pkt.DstPort) +} + func getSocketForPacket(pkt *nfqueue.Packet) *socketStatus { ss := findSocket(pkt) if ss == nil { @@ -163,7 +182,7 @@ func getSocketForPacket(pkt *nfqueue.Packet) *socketStatus { ss.pid = pid return ss } - log.Info("Unable to find socket link socket:[%d] %s", ss.inode, printPacket(pkt, "")) + log.Info("Unable to find socket link socket:[%d] %s", ss.inode, printPacket(pkt)) log.Info("Line was %s", ss.line) return nil } @@ -181,7 +200,7 @@ func findSocket(pkt *nfqueue.Packet) *socketStatus { return &status } } - log.Info("Failed to find socket for packet: %s", printPacket(pkt, "")) + log.Info("Failed to find socket for packet: %s", printPacket(pkt)) return nil } diff --git a/proc_pid.go b/proc/proc_pid.go similarity index 78% rename from proc_pid.go rename to proc/proc_pid.go index 9d0fa06..e247153 100644 --- a/proc_pid.go +++ b/proc/proc_pid.go @@ -1,4 +1,5 @@ -package main +package proc + import ( "os" "strconv" @@ -10,13 +11,13 @@ import ( type ProcInfo struct { - pid int + Uid int + Pid int loaded bool - exePath string - cmdLine string + ExePath string + CmdLine string } - var cacheMap = make(map[uint64]*ProcInfo) func pidCacheLookup(inode uint64) *ProcInfo { @@ -79,10 +80,10 @@ func extractSocket(name string, pid int) { func cacheAddPid(inode uint64, pid int) { pi,ok := cacheMap[inode] - if ok && pi.pid == pid { + if ok && pi.Pid == pid { return } - cacheMap[inode] = &ProcInfo{ pid: pid } + cacheMap[inode] = &ProcInfo{ Pid: pid } } func readdir(dir string) []string { @@ -105,14 +106,14 @@ func (pi *ProcInfo) loadProcessInfo() bool { return true } - exePath, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pi.pid)) + exePath, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pi.Pid)) if err != nil { - log.Warning("Error reading exe link for pid %d: %v", pi.pid, err) + log.Warning("Error reading exe link for pid %d: %v", pi.Pid, err) return false } - bs, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pi.pid)) + bs, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pi.Pid)) if err != nil { - log.Warning("Error reading cmdline for pid %d: %v", pi.pid, err) + log.Warning("Error reading cmdline for pid %d: %v", pi.Pid, err) return false } for i, b := range bs { @@ -121,14 +122,14 @@ func (pi *ProcInfo) loadProcessInfo() bool { } } - finfo, err := os.Stat(fmt.Sprintf("/proc/%d", pi.pid)) + finfo, err := os.Stat(fmt.Sprintf("/proc/%d", pi.Pid)) if err != nil { - log.Warning("Could not stat /proc/%d: %v", pi.pid, err) + log.Warning("Could not stat /proc/%d: %v", pi.Pid, err) return false } finfo.Sys() - pi.exePath = exePath - pi.cmdLine = string(bs) + pi.ExePath = exePath + pi.CmdLine = string(bs) pi.loaded = true return true } diff --git a/prompt.go b/prompt.go index 00c3e21..04edd86 100644 --- a/prompt.go +++ b/prompt.go @@ -92,8 +92,8 @@ func (p *prompter) processPacket(pp *pendingPkt) { addr, int32(pp.pkt.DstPort), pp.pkt.Dst.String(), - uidToUser(pp.proc.uid), - int32(pp.proc.pid)) + uidToUser(pp.pinfo.Uid), + int32(pp.pinfo.Pid)) err := call.Store(&scope, &rule) if err != nil { log.Warning("Error sending dbus RequestPrompt message: %v", err) diff --git a/rules.go b/rules.go index 6c378da..21dd45a 100644 --- a/rules.go +++ b/rules.go @@ -12,6 +12,7 @@ import ( "os" "strconv" "path" + "github.com/subgraph/fw-daemon/proc" ) const ( @@ -77,14 +78,14 @@ const ( FILTER_PROMPT ) -func (rl *RuleList) filter(p *nfqueue.Packet, proc *ProcInfo, hostname string) FilterResult { +func (rl *RuleList) filter(p *nfqueue.Packet, pinfo *proc.ProcInfo, hostname string) FilterResult { if rl == nil { return FILTER_PROMPT } result := FILTER_PROMPT for _, r := range *rl { if r.match(p, hostname) { - log.Info("%s (%s -> %s:%d)", r, proc.exePath, p.Dst.String(), p.DstPort) + log.Info("%s (%s -> %s:%d)", r, pinfo.ExePath, p.Dst.String(), p.DstPort) if r.rtype == RULE_DENY { return FILTER_DENY } else if r.rtype == RULE_ALLOW {