Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monitoring base functional. #1

Merged
merged 2 commits into from
Sep 21, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 238 additions & 56 deletions src/monitor/main.go
Original file line number Diff line number Diff line change
@@ -1,78 +1,260 @@
// example of usage:
// ./monitor -file full_path_to_the_result_file -pid 2,3,4,5 -mount path_to_directory_which_should_be_monitored
// ./monitor -file full_path_to_the_result_file -socket /tmp/monitoring.sock -mount path_to_directory_which_should_be_monitored

// SIGUSR1 - starts monitoring process (here just prints to stdout)
// SIGTERM - stops monitoring and flushes info to file

package main

import (
"bufio"
"encoding/json"
"flag"
"log"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"bitbucket.org/madmo/fanotify"
"github.com/cloudimmunity/pdiscover"

"bufio"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net"
"os"
"os/exec"
"os/signal"
"strconv"
"strings"
"syscall"
)

type event struct {
Pid int
File string
Action string
Pid int32
File string
}

func check(err error) {
if err != nil {
log.Fatalln("monitor error:",err)
}
if err != nil {
log.Fatalln("monitor error:", err)
}
}

func listen_signals() chan bool {
start_work := make(chan bool, 1)
stop_work := make(chan bool, 1)
signals := make(chan os.Signal, 1)

signal.Notify(signals, syscall.SIGUSR1, syscall.SIGTERM)

go func() {
for {
s := <-signals
switch s {
case syscall.SIGUSR1:
start_work <- true
case syscall.SIGTERM:
stop_work <- true
}
}
}()

<-start_work
return stop_work
}

func listen_pids(socket string) chan []int {
p := make(chan []int, 1)

go func() {
l, err := net.Listen("unix", socket)
check(err)
defer l.Close()

c, err := l.Accept()
check(err)
defer c.Close()

d := byte('\n')
data, err := bufio.NewReader(c).ReadBytes(d)
if err != io.EOF && data[len(data)-1] != d {
panic(err)
}

var pids []int
err = json.Unmarshal(data[:len(data)-1], &pids)
check(err)

p <- pids
}()

return p
}

func parse_flags() (string, string, string) {
mp := flag.String("mount", "/", "mount point")
f := flag.String("file", "test", "file")
socket := flag.String("socket", "/tmp/monitoring.sock", "unix socket")
flag.Parse()
return *socket, *mp, *f
}

func get_files(events chan map[event]bool, pids_map chan map[int][]int, pids chan []int) []string {
p := <-pids
pm := <-pids_map
e := <-events
all_pids := make(map[int]bool, 0)

for _, v := range p {
all_pids[v] = true
for _, pl := range pm[v] {
all_pids[pl] = true
}
}

files := make([]string, 0)
for k, _ := range e {
_, found := all_pids[int(k.Pid)]
if found {
files = append(files, k.File)
}
}
return files
}

func write_data(pids []int, mount_point, result_file string) {
f, err := os.Create(result_file)
check(err)
defer f.Close()
w := bufio.NewWriter(f)
func write_data(result_file string, files map[string]bool) {
f, err := os.Create(result_file)
check(err)
defer f.Close()
w := bufio.NewWriter(f)

for _, v := range pids {
event, err := json.Marshal(event{v, "/bin/ping", "open"})
check(err)
w.Write(event)
}
for k, _ := range files {
w.WriteString(k)
w.WriteString("\n")
}
w.Flush()
}

func monitor_process(stop chan bool) chan map[int][]int {
watcher, err := pdiscover.NewAllWatcher(pdiscover.PROC_EVENT_ALL)
check(err)

forks_chan := make(chan map[int][]int, 1)

go func() {
forks := make(map[int][]int)
s := false
for !s {
select {
case <-stop:
s = true
case ev := <-watcher.Fork:
forks[ev.ParentPid] = append(forks[ev.ParentPid], ev.ChildPid)
case <-watcher.Exec:
case <-watcher.Exit:
case err := <-watcher.Error:
log.Println("error: ", err)
panic(err)
}
}
forks_chan <- forks
watcher.Close()
}()

return forks_chan
}

func listen_events(mount_point string, stop chan bool) chan map[event]bool {
nd, err := fanotify.Initialize(fanotify.FAN_CLASS_NOTIF, os.O_RDONLY)
check(err)
err = nd.Mark(fanotify.FAN_MARK_ADD|fanotify.FAN_MARK_MOUNT, fanotify.FAN_ACCESS|fanotify.FAN_OPEN, -1, mount_point)
check(err)

events_chan := make(chan map[event]bool, 1)

go func() {
events := make(map[event]bool, 1)
s := false
for !s {
select {
case <-stop:
s = true
default:
data, err := nd.GetEvent()
check(err)
path, err := os.Readlink(fmt.Sprintf("/proc/self/fd/%d", data.File.Fd()))
check(err)
e := event{data.Pid, path}
data.File.Close()
events[e] = true
}
}
events_chan <- events
}()

return events_chan
}

func files_to_inodes(files []string) []int {
cmd := "/usr/bin/stat"
args := []string{"-L", "-c", "%i"}
args = append(args, files...)
inodes := make([]int, 0)

c := exec.Command(cmd, args...)
out, _ := c.Output()
c.Wait()
for _, i := range strings.Split(string(out), "\n") {
inode, err := strconv.Atoi(strings.TrimSpace(i))
if err != nil {
continue
}
inodes = append(inodes, inode)
}
return inodes
}

func find_symlinks(files []string, mp string) map[string]bool {
cmd := "/usr/bin/find"
args := []string{"-L", mp, "-mount", "-printf", "%i %p\n"}
c := exec.Command(cmd, args...)
out, _ := c.Output()
c.Wait()

w.Flush()
os.Exit(0)
inodes := files_to_inodes(files)
inode_to_files := make(map[int][]string)

for _, v := range strings.Split(string(out), "\n") {
v = strings.TrimSpace(v)
info := strings.Split(v, " ")
inode, err := strconv.Atoi(info[0])
if err != nil {
continue
}
inode_to_files[inode] = append(inode_to_files[inode], info[1])
}

result := make(map[string]bool, 0)
for _, i := range inodes {
v := inode_to_files[i]
for _, f := range v {
result[f] = true
}
}
return result
}

func main() {
sigs_start := make(chan os.Signal, 1)
sigs_stop := make(chan os.Signal, 1)

signal.Notify(sigs_start, syscall.SIGUSR1)
signal.Notify(sigs_stop, syscall.SIGTERM)

pids := flag.String("pid", "1, 2", "pids")
mp := flag.String("mount", "/", "mount point")
rf := flag.String("file", "test", "file")
flag.Parse()

numbers := strings.Split(*pids, ",")
pid_slice := make([]int, len(numbers))

for i, v := range numbers {
n, err := strconv.Atoi(v)
check(err)
pid_slice[i] = n
}

for {
select {
case <-sigs_start:
log.Println("start working")
case <-sigs_stop:
write_data(pid_slice, *mp, *rf)
}
}
socket, mount_point, file := parse_flags()

pids := listen_pids(socket)
stop_work := listen_signals()
stop_events := make(chan bool, 1)
events := listen_events(mount_point, stop_events)

stop_process := make(chan bool, 1)
pids_map := monitor_process(stop_process)

<-stop_work
stop_events <- true
stop_process <- true
files := get_files(events, pids_map, pids)
all_files := find_symlinks(files, mount_point)
write_data(file, all_files)
}