mirror of https://github.com/subgraph/fw-daemon
				
				
				
			Cached DNS name lookups now failover to global cache only populated by local resolver. Added proc-coroner module for detecting process deaths. procsnitch updated to handle multiple levels of "strictness" (necessary to lookup processes generating certain UDP data).shw_dev
							parent
							
								
									51c181a881
								
							
						
					
					
						commit
						c3635093fa
					
				@ -0,0 +1,154 @@
 | 
				
			||||
package pcoroner
 | 
				
			||||
 | 
				
			||||
import (
 | 
				
			||||
	"fmt"
 | 
				
			||||
	"time"
 | 
				
			||||
	"strings"
 | 
				
			||||
	"strconv"
 | 
				
			||||
	"sync"
 | 
				
			||||
	"os"
 | 
				
			||||
	"syscall"
 | 
				
			||||
)
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
type WatchProcess struct {
 | 
				
			||||
	Pid   int
 | 
				
			||||
	Inode uint64
 | 
				
			||||
	Ppid  int
 | 
				
			||||
	Stime int
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
type procCB func(int, interface{})
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
var pmutex = &sync.Mutex{}
 | 
				
			||||
var pidMap map[int]WatchProcess = make(map[int]WatchProcess)
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
func MonitorProcess(pid int) bool {
 | 
				
			||||
	pmutex.Lock()
 | 
				
			||||
	defer pmutex.Unlock()
 | 
				
			||||
 | 
				
			||||
	_, ok := pidMap[pid]
 | 
				
			||||
 | 
				
			||||
	if ok {
 | 
				
			||||
		return false
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	watcher := WatchProcess{Pid: pid}
 | 
				
			||||
	watcher.Inode = 0
 | 
				
			||||
	res := checkProcess(&watcher, true)
 | 
				
			||||
 | 
				
			||||
	if res {
 | 
				
			||||
		pidMap[pid] = watcher
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	return res
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
func UnmonitorProcess(pid int) {
 | 
				
			||||
	pmutex.Lock()
 | 
				
			||||
	defer pmutex.Unlock()
 | 
				
			||||
	delete(pidMap, pid)
 | 
				
			||||
	return
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
func MonitorThread(cbfunc procCB, param interface{}) {
 | 
				
			||||
	for {
 | 
				
			||||
/*		if len(pidMap) == 0 {
 | 
				
			||||
			fmt.Println("TICK")
 | 
				
			||||
		} else { fmt.Println("len = ", len(pidMap)) } */
 | 
				
			||||
		pmutex.Lock()
 | 
				
			||||
		pmutex.Unlock()
 | 
				
			||||
 | 
				
			||||
		for pkey, pval := range pidMap {
 | 
				
			||||
//			fmt.Printf("PID %v -> %v\n", pkey, pval)
 | 
				
			||||
			res := checkProcess(&pval, false)
 | 
				
			||||
 | 
				
			||||
			if !res {
 | 
				
			||||
				delete(pidMap, pkey)
 | 
				
			||||
 | 
				
			||||
				if cbfunc != nil {
 | 
				
			||||
					cbfunc(pkey, param)
 | 
				
			||||
				}
 | 
				
			||||
				continue
 | 
				
			||||
			}
 | 
				
			||||
 | 
				
			||||
		}
 | 
				
			||||
 | 
				
			||||
		time.Sleep(2 * time.Second)
 | 
				
			||||
	}
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
func checkProcess(proc *WatchProcess, init bool) bool {
 | 
				
			||||
	ppath := fmt.Sprintf("/proc/%d/stat", proc.Pid)
 | 
				
			||||
	f, err := os.Open(ppath)
 | 
				
			||||
	if err != nil {
 | 
				
			||||
//		fmt.Printf("Error opening path %s: %s\n", ppath, err)
 | 
				
			||||
		return false
 | 
				
			||||
	}
 | 
				
			||||
	defer f.Close()
 | 
				
			||||
 | 
				
			||||
	fi, err := f.Stat()
 | 
				
			||||
	if err != nil {
 | 
				
			||||
		fmt.Printf("Error calling stat on file %s: %s\n", ppath, err)
 | 
				
			||||
		return false
 | 
				
			||||
	}
 | 
				
			||||
	sb, ok := fi.Sys().(*syscall.Stat_t)
 | 
				
			||||
	if !ok {
 | 
				
			||||
		fmt.Println("Unexpected error reading stat information from proc file")
 | 
				
			||||
	} else if init {
 | 
				
			||||
		proc.Inode = sb.Ino
 | 
				
			||||
	} else {
 | 
				
			||||
		if sb.Ino != proc.Inode {
 | 
				
			||||
			fmt.Printf("/proc inode mismatch for process %d: %v vs %v\n", proc.Pid, sb.Ino, proc.Inode)
 | 
				
			||||
			return false
 | 
				
			||||
		}
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	var buf [512]byte
 | 
				
			||||
	nread, err := f.Read(buf[:])
 | 
				
			||||
	if err != nil {
 | 
				
			||||
		fmt.Printf("Error reading stat for process %d: %v", proc.Pid, err)
 | 
				
			||||
		return true
 | 
				
			||||
	} else if nread <= 0 {
 | 
				
			||||
		fmt.Printf("Unexpected error reading stat for process %d", proc.Pid)
 | 
				
			||||
		return true
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	bstr := string(buf[:])
 | 
				
			||||
//	fmt.Println("sstr = ", bstr)
 | 
				
			||||
 | 
				
			||||
	fields := strings.Split(bstr, " ")
 | 
				
			||||
 | 
				
			||||
	if len(fields) < 22 {
 | 
				
			||||
		fmt.Printf("Unexpected error reading data from /proc stat for process %d", proc.Pid)
 | 
				
			||||
		return true
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	ppid, err := strconv.Atoi(fields[3])
 | 
				
			||||
	if err != nil {
 | 
				
			||||
		ppid = -1
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	if init {
 | 
				
			||||
		proc.Ppid = ppid
 | 
				
			||||
	} else if proc.Ppid != ppid {
 | 
				
			||||
		fmt.Printf("Cached process ppid did not match value in /proc: %v vs %v\n", proc.Ppid, ppid)
 | 
				
			||||
		return false
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	stime, err := strconv.Atoi(fields[21])
 | 
				
			||||
	if err != nil {
 | 
				
			||||
		stime = -1
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	if init {
 | 
				
			||||
		proc.Stime = stime
 | 
				
			||||
	} else if proc.Stime != stime {
 | 
				
			||||
		fmt.Printf("Cached process start time did not match value in /proc: %v vs %v\n", proc.Stime, stime)
 | 
				
			||||
		return false
 | 
				
			||||
	}
 | 
				
			||||
 | 
				
			||||
	return true
 | 
				
			||||
}
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue