summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audit.go84
-rw-r--r--src/basefunc.go115
-rw-r--r--src/deal.go97
-rw-r--r--src/global.go10
-rw-r--r--src/go.mod16
-rw-r--r--src/go.sum59
-rw-r--r--src/godo.go116
-rw-r--r--src/organize.go124
-rw-r--r--src/receive.go29
9 files changed, 650 insertions, 0 deletions
diff --git a/src/audit.go b/src/audit.go
new file mode 100644
index 0000000..ed48691
--- /dev/null
+++ b/src/audit.go
@@ -0,0 +1,84 @@
1package main
2
3import (
4 "fmt"
5 "io"
6 "log"
7 "os"
8
9 "github.com/elastic/go-libaudit/v2"
10)
11
12func read() error {
13 // Write netlink response to a file for further analysis or for writing
14 // tests cases.
15 var diagWriter io.Writer
16 if *diag != "" {
17 f, err := os.OpenFile(*diag, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o600)
18 if err != nil {
19 return err
20 }
21 defer f.Close()
22 diagWriter = f
23 }
24
25 log.Println("starting netlink client")
26
27 var err error
28 var client *libaudit.AuditClient
29 if *receiveOnly {
30 client, err = libaudit.NewMulticastAuditClient(diagWriter)
31 if err != nil {
32 return fmt.Errorf("failed to create receive-only audit client: %w", err)
33 }
34 defer client.Close()
35 } else {
36 client, err = libaudit.NewAuditClient(diagWriter)
37 if err != nil {
38 return fmt.Errorf("failed to create audit client: %w", err)
39 }
40 defer client.Close()
41
42 status, err := client.GetStatus()
43 if err != nil {
44 return fmt.Errorf("failed to get audit status: %w", err)
45 }
46 log.Printf("received audit status=%+v", status)
47
48 if status.Enabled == 0 {
49 log.Println("enabling auditing in the kernel")
50 if err = client.SetEnabled(true, libaudit.WaitForReply); err != nil {
51 return fmt.Errorf("failed to set enabled=true: %w", err)
52 }
53 }
54
55 if status.RateLimit != uint32(*rate) {
56 log.Printf("setting rate limit in kernel to %v", *rate)
57 if err = client.SetRateLimit(uint32(*rate), libaudit.NoWait); err != nil {
58 return fmt.Errorf("failed to set rate limit to unlimited: %w", err)
59 }
60 }
61
62 if status.BacklogLimit != uint32(*backlog) {
63 log.Printf("setting backlog limit in kernel to %v", *backlog)
64 if err = client.SetBacklogLimit(uint32(*backlog), libaudit.NoWait); err != nil {
65 return fmt.Errorf("failed to set backlog limit: %w", err)
66 }
67 }
68
69 if status.Enabled != 2 && *immutable {
70 log.Printf("setting kernel settings as immutable")
71 if err = client.SetImmutable(libaudit.NoWait); err != nil {
72 return fmt.Errorf("failed to set kernel as immutable: %w", err)
73 }
74 }
75
76 log.Printf("sending message to kernel registering our PID (%v) as the audit daemon", os.Getpid())
77 if err = client.SetPID(libaudit.NoWait); err != nil {
78 return fmt.Errorf("failed to set audit PID: %w", err)
79 }
80 }
81
82 coroutine(client)
83 return nil
84}
diff --git a/src/basefunc.go b/src/basefunc.go
new file mode 100644
index 0000000..5fff3e8
--- /dev/null
+++ b/src/basefunc.go
@@ -0,0 +1,115 @@
1package main
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "path/filepath"
8 "regexp"
9 "strconv"
10 "strings"
11 "time"
12)
13
14func figureOutSyscalls() error {
15 NRRegex := regexp.MustCompile(`#define __NR_(.*?) (\d+)$`)
16 file, err := os.Open("/usr/include/asm/unistd_64.h")
17 if err != nil {
18 return err
19 }
20 defer file.Close()
21
22 scanner := bufio.NewScanner(file)
23 for scanner.Scan() {
24 line := scanner.Text()
25 if NRRegex.MatchString(line) {
26 match := NRRegex.FindStringSubmatch(line)
27 num, err := strconv.Atoi(match[2])
28 if err != nil {
29 return err
30 }
31 syscallTable[num] = match[1]
32 }
33 }
34 return nil
35}
36
37func getPid() (int, error) {
38 // 指定要搜索的关键词
39 keyword := "/usr/bin/containerd"
40
41 // 获取/proc目录下的所有子目录
42 procDir, err := filepath.Glob("/proc/*")
43 if err != nil {
44 return 0, err
45 }
46
47 // 遍历子目录,查找包含关键词的进程
48 for _, dir := range procDir {
49 pid, err := strconv.Atoi(filepath.Base(dir))
50 if err != nil {
51 continue // 跳过非PID的目录
52 }
53
54 // 检查进程是否包含关键词
55 if containsKeyword(pid, keyword) {
56 return pid, nil
57 }
58 }
59 err = fmt.Errorf("Error: no containerd process found.")
60 return 0, err
61}
62
63func containsKeyword(pid int, keyword string) bool {
64 // 构造完整的进程命令路径
65 cmdPath := fmt.Sprintf("/proc/%d/cmdline", pid)
66
67 // 打开文件
68 file, err := os.Open(cmdPath)
69 if err != nil {
70 return false
71 }
72 defer file.Close()
73
74 // 读取文件内容
75 scanner := bufio.NewScanner(file)
76 scanner.Split(bufio.ScanLines)
77 for scanner.Scan() {
78 line := scanner.Text()
79 if strings.Contains(line, keyword) {
80 return true
81 }
82 }
83 return false
84}
85
86func getTimeFromStr(timeStr string) (time.Time, error) {
87 timestampFloat, err := strconv.ParseFloat(timeStr, 64)
88 if err != nil {
89 return time.Unix(0, 0), err
90 }
91 secs := int64(timestampFloat)
92 nsecs := int64((timestampFloat - float64(secs)) * 1e9)
93
94 // 只精确到毫秒就够了
95 t := time.Unix(secs, nsecs).Truncate(time.Millisecond)
96 return t, nil
97}
98
99func hexToAscii(hexString string) string {
100 bytes := []byte{}
101 for i := 0; i < len(hexString); i += 2 {
102 hexPair := hexString[i : i+2]
103 // 将十六进制数转换为十进制数
104 decimal, err := strconv.ParseInt(hexPair, 16, 8)
105 if err != nil {
106 return "Invalid hex string"
107 }
108 char := byte(decimal)
109 bytes = append(bytes, char)
110 }
111
112 asciiString := strings.ReplaceAll(string(bytes), "\000", " ")
113
114 return asciiString
115}
diff --git a/src/deal.go b/src/deal.go
new file mode 100644
index 0000000..fd9f788
--- /dev/null
+++ b/src/deal.go
@@ -0,0 +1,97 @@
1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8func deal() {
9 defer wg.Done()
10 var cooked Event
11 var ok bool
12 for {
13 cooked, ok = <-cookedChan
14 if !ok {
15 break
16 }
17 // type Event struct {
18 // timestamp time.Time
19 // pid, ppid int
20 // syscall int
21 // argc int
22 // args []string
23 // cwd string
24 // }
25 // type process struct {
26 // timestamp time.Time
27 // pid, ppid int
28 // argv []string
29 // cwd string
30 // rootfs string
31 // children []int
32 // }
33 switch syscallTable[cooked.syscall] {
34 case "fork", "vfork", "clone":
35 ppid := cooked.ppid
36 pid := cooked.pid
37 parent, ok := pids.Load(ppid)
38 if !ok {
39 break
40 }
41 parent.(*process).children = append(parent.(*process).children, pid)
42 pids.Store(pid, &process{
43 timestamp: cooked.timestamp,
44 pid: cooked.pid,
45 ppid: cooked.ppid,
46 argv: cooked.argv,
47 cwd: cooked.cwd,
48 children: make([]int, 0),
49 })
50 fmt.Printf("%v syscall=%d, ppid=%d, pid=%d, cwd=\"%s\", argc=%d, ", cooked.timestamp, cooked.syscall, cooked.ppid, cooked.pid, cooked.cwd, cooked.argc)
51 for i := 0; i < cooked.argc; i++ {
52 fmt.Printf("arg[%d]=\"%s\", ", i, cooked.argv[i])
53 }
54 fmt.Printf("\n")
55 case "exit", "exit_group":
56 _, ok := pids.Load(cooked.pid)
57 if !ok {
58 break
59 }
60 go deletePid(cooked)
61 }
62 }
63}
64
65func deletePid(cooked Event) {
66 time.Sleep(1 * time.Second)
67 Process, ok := pids.Load(cooked.pid)
68 if !ok {
69 return
70 }
71 pProcess := Process.(*process)
72
73 // 先从爹那里注销户籍
74 parent, ok := pids.Load(pProcess.ppid)
75 if ok {
76 pParent := parent.(*process)
77 for i, child := range pParent.children {
78 if child == pProcess.pid {
79 pParent.children = append(pParent.children[:i], pParent.children[i+1:]...)
80 break
81 }
82 }
83 }
84
85 // 子进程需要收容
86 for i := 0; i < len(pProcess.children); i++ {
87 child, ok := pids.Load(pProcess.children[i])
88 if ok {
89 child.(*process).ppid = 1
90 }
91 }
92
93 // 可以去死了
94 pids.Delete(cooked.pid)
95 _, ok = pids.Load(cooked.pid)
96 fmt.Printf("%v Goodbye, %d! ok = %v\n", time.Now(), cooked.pid, ok)
97}
diff --git a/src/global.go b/src/global.go
new file mode 100644
index 0000000..4e08866
--- /dev/null
+++ b/src/global.go
@@ -0,0 +1,10 @@
1package main
2
3import "sync"
4
5var pids sync.Map // 古希腊掌管进程的神,int->*process
6var wg sync.WaitGroup // 掌管协程
7var rawChan chan interface{} // 从接收到整理的管道
8var cookedChan chan Event // 整理好的信息的管道
9var syscallTable [500]string //记录一下系统调用
10var containerdPid int
diff --git a/src/go.mod b/src/go.mod
new file mode 100644
index 0000000..2969b32
--- /dev/null
+++ b/src/go.mod
@@ -0,0 +1,16 @@
1module godo
2
3go 1.21.5
4
5require (
6 github.com/elastic/go-libaudit/v2 v2.5.0
7 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
8 gopkg.in/yaml.v3 v3.0.1
9)
10
11require (
12 go.uber.org/atomic v1.7.0 // indirect
13 go.uber.org/multierr v1.7.0 // indirect
14 golang.org/x/sys v0.11.0 // indirect
15 gopkg.in/yaml.v2 v2.4.0 // indirect
16)
diff --git a/src/go.sum b/src/go.sum
new file mode 100644
index 0000000..7ce498a
--- /dev/null
+++ b/src/go.sum
@@ -0,0 +1,59 @@
1github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4github.com/elastic/go-libaudit/v2 v2.5.0 h1:5OK919QRnGtcjVBz3n/cs5F42im1mPlVTA9TyIn2K54=
5github.com/elastic/go-libaudit/v2 v2.5.0/go.mod h1:AjlnhinP+kKQuUJoXLVrqxBM8uyhQmkzoV6jjsCFP4Q=
6github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4=
7github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU=
8github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
9github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
10github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
11github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
12github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
13github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
14github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
15github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
16github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
17github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
18github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
19go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
20go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
21go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
22go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
23golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
24golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
25golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
26golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
27golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
28golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
29golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
30golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
31golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
32golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
33golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
34golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
35golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
36golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
37golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
38golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
41golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
43golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
44golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
45golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
46golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
47golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
48golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
49golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
50golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
51golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
52gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
53gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
54gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
55gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
56gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
57gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
58gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
59gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/src/godo.go b/src/godo.go
new file mode 100644
index 0000000..6f73893
--- /dev/null
+++ b/src/godo.go
@@ -0,0 +1,116 @@
1package main
2
3import (
4 "flag"
5 "fmt"
6 "log"
7 "os"
8 "os/exec"
9 "time"
10
11 "github.com/elastic/go-libaudit/v2"
12)
13
14var (
15 fs = flag.NewFlagSet("audit", flag.ExitOnError)
16 diag = fs.String("diag", "", "dump raw information from kernel to file")
17 rate = fs.Uint("rate", 0, "rate limit in kernel (default 0, no rate limit)")
18 backlog = fs.Uint("backlog", 8192, "backlog limit")
19 immutable = fs.Bool("immutable", false, "make kernel audit settings immutable (requires reboot to undo)")
20 receiveOnly = fs.Bool("ro", false, "receive only using multicast, requires kernel 3.16+")
21)
22
23type Event struct {
24 timestamp time.Time
25 pid, ppid int
26 syscall int
27 argc int
28 argv []string
29 cwd string
30}
31
32type process struct {
33 timestamp time.Time
34 pid, ppid int
35 argv []string
36 cwd string
37 rootfs string
38 children []int
39}
40
41func main() {
42 // 检查用户身份,并添加auditd规则,监听所有syscall
43 if os.Geteuid() != 0 {
44 fmt.Printf("Err: Please run me as root, %d!\n", os.Getegid())
45 return
46 }
47
48 // 所有的系统调用号与名称的关系
49 err := figureOutSyscalls()
50 if err != nil {
51 fmt.Printf("Error figuring out syscall numbers: %v\n", err)
52 }
53
54 syscall := [6]string{"fork", "vfork", "clone", "execve", "exit", "exit_group"}
55 var auditCmd *exec.Cmd
56 auditCmd = exec.Command("auditctl", "-D") // 清空所有规则
57 auditCmd.Run()
58 // 设置监听规则
59 for i := 0; i < len(syscall); i++ {
60 auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", syscall[i])
61 auditCmd.Run()
62 }
63
64 // 查找pid
65 containerdPid, err = getPid()
66 if err != nil {
67 fmt.Printf("Error finding containerd: %v\n", err)
68 return
69 }
70
71 // 创世之神,1号进程
72 // pids[1] = &process{rootfs: "/", children: make([]int, 0)}
73 // pids[1].children = append(pids[1].children, containerdPid)
74 // 1号进程还是不要在进程树上直接出现了,不然它的小儿子们都会出现
75
76 // /usr/bin/containerd,也就是我们最关注的进程
77 // pids[containerdPid] = &process{rootfs: "/", children: make([]int, 0)}
78 pids.Store(containerdPid, &process{
79 ppid: 1,
80 pid: containerdPid,
81 argv: make([]string, 0),
82 cwd: "/",
83 rootfs: "/",
84 children: make([]int, 0),
85 })
86 p, ok := pids.Load(containerdPid)
87 if !ok {
88 fmt.Printf("???\n")
89 return
90 }
91 p.(*process).argv = append(p.(*process).argv, "/usr/bin/containerd")
92
93 // 开始运行,解析命令行参数后监听
94 if err := fs.Parse(os.Args[1:]); err != nil {
95 log.Fatal(err)
96 }
97
98 if err := read(); err != nil {
99 log.Fatalf("error: %v", err)
100 }
101}
102
103func coroutine(client *libaudit.AuditClient) {
104 // 各协程至此开始
105 rawChan = make(chan interface{})
106 cookedChan = make(chan Event)
107 wg.Add(1)
108 go receive(client)
109 wg.Add(1)
110 go orgnaze()
111 wg.Add(1)
112 go deal()
113
114 wg.Wait()
115 time.Sleep(2 * time.Second)
116}
diff --git a/src/organize.go b/src/organize.go
new file mode 100644
index 0000000..025d8c0
--- /dev/null
+++ b/src/organize.go
@@ -0,0 +1,124 @@
1package main
2
3import (
4 "regexp"
5 "strconv"
6 "strings"
7
8 "github.com/elastic/go-libaudit/v2"
9 "github.com/elastic/go-libaudit/v2/auparse"
10)
11
12func orgnaze() {
13 defer wg.Done()
14 defer close(cookedChan)
15 // 接收信息
16 var raw interface{}
17 var ok bool
18 var rawEvent libaudit.RawAuditMessage
19 // 事件信息
20 var eventId, argc int
21 var err [6]error
22 var event, cooked Event
23 // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的
24 eventTable := make(map[int]*Event)
25 // 要用的正则匹配列表
26 syscallRegex := regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+).*?ppid=(\d+) pid=(\d+).*?$`)
27 execveRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`)
28 argsRegex := regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`)
29 cwdRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`)
30 proctitleRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`)
31 eoeRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`)
32 for {
33 raw, ok = <-rawChan
34 if !ok {
35 break
36 }
37 rawEvent = raw.(libaudit.RawAuditMessage)
38
39 // type Event struct {
40 // timestamp time.Time
41 // pid, ppid int
42 // syscall int
43 // argc int
44 // args []string
45 // cwd string
46 // }
47 switch rawEvent.Type {
48 case auparse.AUDIT_SYSCALL:
49 if syscallRegex.Match(rawEvent.Data) {
50 match := syscallRegex.FindSubmatch(rawEvent.Data)
51 event.timestamp, err[0] = getTimeFromStr(string(match[1]))
52 eventId, err[1] = strconv.Atoi(string(match[2]))
53 event.syscall, err[2] = strconv.Atoi(string(match[3]))
54 event.ppid, err[3] = strconv.Atoi(string(match[4]))
55 event.pid, err[4] = strconv.Atoi(string(match[5]))
56 eventTable[eventId] = &Event{
57 timestamp: event.timestamp,
58 syscall: event.syscall,
59 ppid: event.ppid,
60 pid: event.pid,
61 argc: 0,
62 argv: make([]string, 0),
63 cwd: "",
64 }
65 }
66 case auparse.AUDIT_EXECVE:
67 if execveRegex.Match(rawEvent.Data) {
68 match := execveRegex.FindSubmatch(rawEvent.Data)
69 eventId, err[0] = strconv.Atoi(string(match[1]))
70 argc, err[1] = strconv.Atoi(string(match[2]))
71 if err[0] == nil && err[1] == nil && argsRegex.Match(rawEvent.Data) {
72 match := argsRegex.FindAllSubmatch(rawEvent.Data, -1)
73 for i := 0; i < argc; i++ {
74 if len(match[i][2]) == 0 {
75 // 代表着匹配到的是十六进制数
76 str := hexToAscii(string(match[i][3]))
77 eventTable[eventId].argv = append(eventTable[eventId].argv, str)
78 } else {
79 eventTable[eventId].argv = append(eventTable[eventId].argv, string(match[i][2]))
80 }
81 }
82 eventTable[eventId].argc = argc
83 }
84 }
85 // case auparse.AUDIT_PATH:
86 case auparse.AUDIT_CWD:
87 if cwdRegex.Match(rawEvent.Data) {
88 match := cwdRegex.FindSubmatch(rawEvent.Data)
89 eventId, err[0] = strconv.Atoi(string(match[1]))
90 eventTable[eventId].cwd = string(match[2])
91 }
92 case auparse.AUDIT_PROCTITLE:
93 if proctitleRegex.Match(rawEvent.Data) {
94 var cmdline string
95 var pEvent *Event
96 match := proctitleRegex.FindSubmatch(rawEvent.Data)
97 eventId, err[0] = strconv.Atoi(string(match[1]))
98 pEvent = eventTable[eventId]
99 if pEvent.argc == 0 {
100 // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数
101 if match[3] == nil {
102 // PROCTITLE写的是十六进制,转换为字符串
103 cmdline = hexToAscii(string(match[4]))
104 } else {
105 cmdline = string(match[3])
106 }
107 pEvent.argv = strings.Split(cmdline, " ")
108 pEvent.argc = len(eventTable[eventId].argv)
109 }
110 }
111 case auparse.AUDIT_EOE:
112 if eoeRegex.Match(rawEvent.Data) {
113 match := eoeRegex.FindSubmatch(rawEvent.Data)
114 eventId, err[0] = strconv.Atoi(string(match[1]))
115 // ATTENTION: 事件整理完毕,即刻发出,是否合理呢?
116 cooked = *eventTable[eventId] // 应当采用深拷贝吗?有待实验
117 cookedChan <- cooked
118 delete(eventTable, eventId) //发出之后就从信息表扔掉,死人别占地
119 }
120 default:
121 // ATTENTION: 这里也需要做防护
122 }
123 }
124}
diff --git a/src/receive.go b/src/receive.go
new file mode 100644
index 0000000..c0dea00
--- /dev/null
+++ b/src/receive.go
@@ -0,0 +1,29 @@
1package main
2
3import (
4 "fmt"
5
6 "github.com/elastic/go-libaudit/v2"
7 "github.com/elastic/go-libaudit/v2/auparse"
8 "github.com/mohae/deepcopy"
9)
10
11func receive(r *libaudit.AuditClient) error {
12 defer wg.Done()
13 defer close(rawChan)
14 for {
15 rawEvent, err := r.Receive(false)
16 if err != nil {
17 return fmt.Errorf("receive failed: %w", err)
18 }
19
20 // Messages from 1300-2999 are valid audit messages.
21 if rawEvent.Type < auparse.AUDIT_USER_AUTH ||
22 rawEvent.Type > auparse.AUDIT_LAST_USER_MSG2 {
23 continue
24 }
25
26 rawEventMessage := deepcopy.Copy(*rawEvent)
27 rawChan <- rawEventMessage
28 }
29}