Moved /proc parsing code into a new package

pull/16/head
Bruce Leidl 9 years ago
parent bb2a0f96a4
commit 30a21eaa57

@ -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")

@ -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 {

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

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

@ -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)

@ -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 {

Loading…
Cancel
Save