summaryrefslogtreecommitdiffstats
path: root/src/godo.go
blob: 923ef858c50388805c9b6feaae1affe34693e738 (plain) (blame)
package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"netlink"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"github.com/elastic/go-libaudit/v2"
)

var (
	fs          = flag.NewFlagSet("audit", flag.ExitOnError)
	diag        = fs.String("diag", "", "dump raw information from kernel to file")
	rate        = fs.Uint("rate", 0, "rate limit in kernel (default 0, no rate limit)")
	backlog     = fs.Uint("backlog", 8192, "backlog limit")
	immutable   = fs.Bool("immutable", false, "make kernel audit settings immutable (requires reboot to undo)")
	receiveOnly = fs.Bool("ro", false, "receive only using multicast, requires kernel 3.16+")
)

func main() {
	// 检查用户身份,并添加auditd规则,监听所有syscall
	if os.Geteuid() != 0 {
		fmt.Printf("Err: Please run me as root, %d!\n", os.Getegid())
		return
	}

	// 所有的系统调用号与名称的关系
	err := figureOutSyscalls()
	if err != nil {
		fmt.Printf("Error figuring out syscall numbers: %v\n", err)
	}

	exec.Command("auditctl", "-D").Run()
	exec.Command("auditctl", "-b", "1000000000").Run()
	exec.Command("auditctl", "--reset-lost").Run()

	var auditCmd *exec.Cmd

	pidSyscall := []string{"execve"}
	// // 设置监听规则
	for i := 0; i < len(pidSyscall); i++ {
		auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", pidSyscall[i])
		auditCmd.Run()
	}

	// 监听文件的消息
	fileSyscall := []string{"open", "close", "write"}
	// fileSyscall := []string{"open", "write", "creat", "unlink", "opendir", "mkdir", "rmdir", "chmod", "fchmod", "chown", "fchown", "lchown", "flock"}
	for i := 0; i < len(fileSyscall); i++ {
		auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", fileSyscall[i])
		auditCmd.Run()
	}

	// 查找pid
	containerdPid, err = getPid()
	if err != nil {
		fmt.Printf("Error finding containerd: %v\n", err)
		return
	}

	// 创世之神,1号进程
	// 1号进程还是不要在进程树上直接出现了,不然它的小儿子们都会出现
	// /usr/bin/containerd,也就是我们最关注的进程

	// 开始运行,解析命令行参数后监听
	if err := fs.Parse(os.Args[1:]); err != nil {
		log.Fatal(err)
	}

	if err := read(); err != nil {
		log.Fatalf("error: %v", err)
	}
}

func coroutine(client *libaudit.AuditClient) {
	// 各协程至此开始
	rawChan = make(chan interface{})
	cookedChan = make(chan Event)

	wg.Add(1)
	go procWatch()

	wg.Add(1)
	go receive(client)
	wg.Add(1)
	go orgnaze()
	wg.Add(1)
	go deal()

	wg.Wait()
	time.Sleep(2 * time.Second)
}

func procWatch() error {
	ns, err := netlink.NewNetlinkSocket(syscall.NETLINK_CONNECTOR, 12345)
	if err != nil {
		fmt.Printf("Error creating socket: %v\n", err)
		return err
	}
	defer ns.Close()
	for {
		res, err := ns.Receive(20)
		if err != nil {
			fmt.Printf("Error recv: %v\n", err)
			continue
		}
		for i := 0; i < len(res); i++ {
			procEvent := netlink.ParseProcEvent(res[i].Data)
			switch procEvent.What {
			case netlink.PROC_EVENT_FORK:
				data := procEvent.Data.(netlink.ProcEventFork)
				cooked := Event{
					tag:        NEWPID,
					timestamp:  time.Now(),
					pid:        int(data.ChildPid),
					tgid:       int(data.ChildTgid),
					ppid:       int(data.ParentPid),
					parentTgid: int(data.ParentTgid),
				}
				checkProc(&cooked)
				cookedChan <- cooked
			case netlink.PROC_EVENT_EXIT:
				data := procEvent.Data.(netlink.ProcEventExit)
				cooked := Event{
					tag:         PIDEXIT,
					timestamp:   time.Now(),
					pid:         int(data.ProcessPid),
					exit_code:   uint64(data.ExitCode),
					exit_signal: int(data.ExitSignal),
				}
				cookedChan <- cooked
			default:
			}
		}
	}
}

func checkProc(pCooked *Event) {
	fileName := fmt.Sprintf("/proc/%d/task/%d/cmdline", pCooked.tgid, pCooked.pid)
	fd, err := os.Open(fileName)
	if err != nil {
		fmt.Printf("Err: %v\n", err)
		return
	}

	scanner := bufio.NewScanner(fd)
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		line := scanner.Text()
		pCooked.argv = append(pCooked.argv, strings.Split(line, "\x00")...)
	}
	pCooked.argc = len(pCooked.argv)
	fd.Close()

	fileName = fmt.Sprintf("/proc/%d/task/%d/cwd", pCooked.tgid, pCooked.pid)
	pCooked.cwd, err = os.Readlink(fileName)
	if err != nil {
		fmt.Printf("Err readlink %s: %v\n", fileName, err)
		pCooked.cwd = ""
	}
}