diff options
author | We-unite <3205135446@qq.com> | 2024-08-09 13:56:37 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-08-12 14:16:51 +0800 |
commit | 3e49a044d22635157916651f0acb5a062397b34b (patch) | |
tree | 254cd9a2605fa003f4579e7c5510e6e2aea19375 /listener | |
parent | ea32e017e579f168d87732893335c38d539ac2f1 (diff) | |
download | godo-3e49a044d22635157916651f0acb5a062397b34b.tar.gz godo-3e49a044d22635157916651f0acb5a062397b34b.zip |
Add db structure, fix filePath, start filtering
This commit I made several changes:
- Use structure instead of simple bson.M(interface{}). bson.M has
some shortcomings: 1) It makes the database in chaos and hard to
read, but this's not important; 2) Some entrys may has more or
less content than others, which makes it hard to decode and filt.
So I design new data structure to encode and decode. Hopes that
there's no bugs.
- Fix the way to calculate file path. The original method is to add
all the PATH entries together, that's totally wrong! PATH entry
has several types, as it shows in "objtype". I can't find it in
the kernel src code, so what i know is just "PARENT" means the dir
the file is in, while the filename itself has the path, so we
whould ignore all "PARENT"s. When the src code is found, we should
check it again.
- Fix bugs in updating. The update function of mongodb is set to
required to has a '$' such as 'set'/'push', so when we update a
whole doc, we should use replace but not update function. And,
we should never ignore the error infomation it gives us.
Hope that there's no more bugs for this Big Change.
Now its' time to write filter as well as viewer. Best wishes with
NO BUGS!
Diffstat (limited to 'listener')
-rw-r--r-- | listener/audit.go | 84 | ||||
-rw-r--r-- | listener/basefunc.go | 129 | ||||
-rw-r--r-- | listener/deal.go | 269 | ||||
-rw-r--r-- | listener/global.go | 84 | ||||
-rw-r--r-- | listener/go.mod | 26 | ||||
-rw-r--r-- | listener/go.sum | 96 | ||||
-rw-r--r-- | listener/go.work | 6 | ||||
-rw-r--r-- | listener/go.work.sum | 4 | ||||
-rw-r--r-- | listener/godo.go | 176 | ||||
-rw-r--r-- | listener/mongo.go | 122 | ||||
m--------- | listener/netlink | 0 | ||||
-rw-r--r-- | listener/organize.go | 291 | ||||
-rw-r--r-- | listener/receive.go | 29 |
13 files changed, 1316 insertions, 0 deletions
diff --git a/listener/audit.go b/listener/audit.go new file mode 100644 index 0000000..ed48691 --- /dev/null +++ b/listener/audit.go | |||
@@ -0,0 +1,84 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "io" | ||
6 | "log" | ||
7 | "os" | ||
8 | |||
9 | "github.com/elastic/go-libaudit/v2" | ||
10 | ) | ||
11 | |||
12 | func 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/listener/basefunc.go b/listener/basefunc.go new file mode 100644 index 0000000..2f39507 --- /dev/null +++ b/listener/basefunc.go | |||
@@ -0,0 +1,129 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "fmt" | ||
6 | "os" | ||
7 | "os/exec" | ||
8 | "path/filepath" | ||
9 | "strconv" | ||
10 | "strings" | ||
11 | "time" | ||
12 | ) | ||
13 | |||
14 | func figureOutSyscalls() error { | ||
15 | cmd := exec.Command("ausyscall", "--dump") | ||
16 | stdout, err := cmd.StdoutPipe() | ||
17 | if err != nil { | ||
18 | return err | ||
19 | } | ||
20 | |||
21 | if err := cmd.Start(); err != nil { | ||
22 | return err | ||
23 | } | ||
24 | |||
25 | scanner := bufio.NewScanner(stdout) | ||
26 | for i := 0; scanner.Scan(); i++ { | ||
27 | if i == 0 { | ||
28 | continue | ||
29 | } | ||
30 | line := scanner.Text() | ||
31 | parts := strings.Split(line, "\t") | ||
32 | if len(parts) != 2 { | ||
33 | return fmt.Errorf("invalid ausyscall format") | ||
34 | } | ||
35 | num, err := strconv.Atoi(parts[0]) | ||
36 | if err != nil { | ||
37 | return err | ||
38 | } | ||
39 | syscallTable[num] = parts[1] | ||
40 | } | ||
41 | |||
42 | if err := scanner.Err(); err != nil { | ||
43 | return err | ||
44 | } | ||
45 | if err := cmd.Wait(); err != nil { | ||
46 | return err | ||
47 | } | ||
48 | return nil | ||
49 | } | ||
50 | |||
51 | func getPid() (int, error) { | ||
52 | // 指定要搜索的关键词 | ||
53 | keyword := "/usr/bin/containerd" | ||
54 | |||
55 | // 获取/proc目录下的所有子目录 | ||
56 | procDir, err := filepath.Glob("/proc/*") | ||
57 | if err != nil { | ||
58 | return 0, err | ||
59 | } | ||
60 | |||
61 | // 遍历子目录,查找包含关键词的进程 | ||
62 | for _, dir := range procDir { | ||
63 | pid, err := strconv.Atoi(filepath.Base(dir)) | ||
64 | if err != nil { | ||
65 | continue // 跳过非PID的目录 | ||
66 | } | ||
67 | |||
68 | // 检查进程是否包含关键词 | ||
69 | if containsKeyword(pid, keyword) { | ||
70 | return pid, nil | ||
71 | } | ||
72 | } | ||
73 | err = fmt.Errorf("Error: no containerd process found.") | ||
74 | return 0, err | ||
75 | } | ||
76 | |||
77 | func containsKeyword(pid int, keyword string) bool { | ||
78 | // 构造完整的进程命令路径 | ||
79 | cmdPath := fmt.Sprintf("/proc/%d/cmdline", pid) | ||
80 | |||
81 | // 打开文件 | ||
82 | file, err := os.Open(cmdPath) | ||
83 | if err != nil { | ||
84 | return false | ||
85 | } | ||
86 | defer file.Close() | ||
87 | |||
88 | // 读取文件内容 | ||
89 | scanner := bufio.NewScanner(file) | ||
90 | scanner.Split(bufio.ScanLines) | ||
91 | for scanner.Scan() { | ||
92 | line := scanner.Text() | ||
93 | if strings.Contains(line, keyword) { | ||
94 | return true | ||
95 | } | ||
96 | } | ||
97 | return false | ||
98 | } | ||
99 | |||
100 | func getTimeFromStr(timeStr string) (time.Time, error) { | ||
101 | timestampFloat, err := strconv.ParseFloat(timeStr, 64) | ||
102 | if err != nil { | ||
103 | return time.Unix(0, 0), err | ||
104 | } | ||
105 | secs := int64(timestampFloat) | ||
106 | nsecs := int64((timestampFloat - float64(secs)) * 1e9) | ||
107 | |||
108 | // 只精确到毫秒就够了 | ||
109 | t := time.Unix(secs, nsecs).Truncate(time.Millisecond) | ||
110 | return t, nil | ||
111 | } | ||
112 | |||
113 | func hexToAscii(hexString string) string { | ||
114 | bytes := []byte{} | ||
115 | for i := 0; i < len(hexString); i += 2 { | ||
116 | hexPair := hexString[i : i+2] | ||
117 | // 将十六进制数转换为十进制数 | ||
118 | decimal, err := strconv.ParseInt(hexPair, 16, 8) | ||
119 | if err != nil { | ||
120 | return "Invalid hex string" | ||
121 | } | ||
122 | char := byte(decimal) | ||
123 | bytes = append(bytes, char) | ||
124 | } | ||
125 | |||
126 | asciiString := strings.ReplaceAll(string(bytes), "\000", " ") | ||
127 | |||
128 | return asciiString | ||
129 | } | ||
diff --git a/listener/deal.go b/listener/deal.go new file mode 100644 index 0000000..8f77431 --- /dev/null +++ b/listener/deal.go | |||
@@ -0,0 +1,269 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "os" | ||
6 | "syscall" | ||
7 | "time" | ||
8 | |||
9 | "go.mongodb.org/mongo-driver/bson" | ||
10 | ) | ||
11 | |||
12 | const ( | ||
13 | dbName string = "test" | ||
14 | pidColName string = "pids" | ||
15 | fdColName string = "fds" | ||
16 | fileColName string = "files" | ||
17 | ) | ||
18 | |||
19 | var pidCol, fdCol, fileCol mongoClient | ||
20 | var err error | ||
21 | |||
22 | func deal() { | ||
23 | defer wg.Done() | ||
24 | var cooked Event | ||
25 | var ok bool | ||
26 | |||
27 | if err = pidCol.init(dbName, pidColName); err != nil { | ||
28 | fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err) | ||
29 | return | ||
30 | } | ||
31 | err = pidCol.InsertOne(Process{ | ||
32 | Ppid: 1, | ||
33 | Pid: containerdPid, | ||
34 | Cwd: "/", | ||
35 | Children: make([]int, 0), | ||
36 | Star: true, | ||
37 | }) | ||
38 | if err != nil { | ||
39 | fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err) | ||
40 | return | ||
41 | } | ||
42 | |||
43 | if err = fdCol.init(dbName, fdColName); err != nil { | ||
44 | fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err) | ||
45 | return | ||
46 | } | ||
47 | if err = fileCol.init(dbName, fileColName); err != nil { | ||
48 | fmt.Fprintf(os.Stderr, "Error while initing the mongodb: %v\n", err) | ||
49 | } | ||
50 | |||
51 | defer pidCol.Disconnect() | ||
52 | defer fdCol.Disconnect() | ||
53 | defer fileCol.Disconnect() | ||
54 | |||
55 | for { | ||
56 | cooked, ok = <-cookedChan | ||
57 | if !ok { | ||
58 | break | ||
59 | } | ||
60 | |||
61 | switch cooked.tag { | ||
62 | case NEWPID: | ||
63 | go dealNewPid(cooked) | ||
64 | case EXECVE: | ||
65 | go dealExecve(cooked) | ||
66 | case PIDEXIT: | ||
67 | go deletePid(cooked) | ||
68 | case FILEOPEN: | ||
69 | go fileOpen(cooked) | ||
70 | case FILEWRITE: | ||
71 | go fileWrite(cooked) | ||
72 | case FILECLOSE: | ||
73 | go fileClose(cooked) | ||
74 | case PIVOTROOT: | ||
75 | go pivotRoot(cooked) | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | func deletePid(cooked Event) { | ||
81 | // 在这套逻辑里,孩子是不需要收容的,因为我们根本就不看ppid来工作 | ||
82 | // 父节点那里也不需要销户 | ||
83 | // 理论上这里需要关闭所有文件描述符,但为了处理效率,留给后续流程 | ||
84 | err := pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{ | ||
85 | "$set": bson.M{ | ||
86 | "exit_timestamp": cooked.timestamp, | ||
87 | "exit_code": cooked.exit_code, | ||
88 | "exit_signal": cooked.exit_signal, | ||
89 | }, | ||
90 | }) | ||
91 | if err != nil { | ||
92 | fmt.Fprintf(os.Stderr, "Err updating: %v\n", err) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | func dealNewPid(cooked Event) { | ||
97 | // 自身是否已经记录 | ||
98 | var docRes []Process | ||
99 | err = pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes) | ||
100 | if err != nil { | ||
101 | fmt.Fprintf(os.Stderr, "Err finding: %v\n", err) | ||
102 | return | ||
103 | } | ||
104 | |||
105 | if len(docRes) != 0 { | ||
106 | // 进程原本就存在,换言之别的消息先到了 | ||
107 | // 所有先行抵达的消息必须保留execve/children字段 | ||
108 | docRes[0].Ppid = cooked.ppid | ||
109 | docRes[0].ParentTgid = cooked.parentTgid | ||
110 | docRes[0].Pid = cooked.pid | ||
111 | docRes[0].Tgid = cooked.tgid | ||
112 | docRes[0].Cwd = cooked.cwd | ||
113 | docRes[0].Comm = cooked.comm | ||
114 | docRes[0].Args = cooked.argv | ||
115 | |||
116 | err := pidCol.ReplaceOne(bson.M{"pid": cooked.pid}, docRes[0]) | ||
117 | if err != nil { | ||
118 | fmt.Fprintf(os.Stderr, "Err replaceing: %v\n", err) | ||
119 | } | ||
120 | } else { | ||
121 | // 这进程本是新修的 | ||
122 | err := pidCol.InsertOne(Process{ | ||
123 | StartTimestamp: cooked.timestamp, | ||
124 | Ppid: cooked.ppid, | ||
125 | ParentTgid: cooked.parentTgid, | ||
126 | Pid: cooked.pid, | ||
127 | Tgid: cooked.tgid, | ||
128 | Args: cooked.argv, | ||
129 | Comm: cooked.comm, | ||
130 | Cwd: cooked.cwd, | ||
131 | Execve: make([]Exec, 0), | ||
132 | Children: make([]int, 0), | ||
133 | }) | ||
134 | if err != nil { | ||
135 | fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err) | ||
136 | } | ||
137 | } | ||
138 | |||
139 | err := pidCol.UpdateOne(bson.M{"pid": cooked.ppid}, bson.M{ | ||
140 | "$push": bson.M{ | ||
141 | "children": cooked.pid, | ||
142 | }, | ||
143 | }) | ||
144 | if err != nil { | ||
145 | fmt.Fprintf(os.Stderr, "Err updating: %v\n", err) | ||
146 | } | ||
147 | } | ||
148 | |||
149 | func dealExecve(cooked Event) { | ||
150 | var docRes []Process | ||
151 | // 首先检查进程是否存在,如不存在则为之创建 | ||
152 | err = pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes) | ||
153 | if err != nil { | ||
154 | return | ||
155 | } | ||
156 | |||
157 | if len(docRes) == 1 { | ||
158 | // 自身已在,直接记录 | ||
159 | docRes[0].Execve = append(docRes[0].Execve, Exec{ | ||
160 | Timestamp: cooked.timestamp, | ||
161 | ExecArgs: cooked.argv, | ||
162 | }) | ||
163 | |||
164 | err := pidCol.ReplaceOne(bson.M{"pid": cooked.pid}, docRes[0]) | ||
165 | if err != nil { | ||
166 | fmt.Fprintf(os.Stderr, "Err replacing: %v\n", err) | ||
167 | } | ||
168 | } else { | ||
169 | // 先fork抵达,插入 | ||
170 | process := Process{ | ||
171 | Ppid: cooked.ppid, | ||
172 | Pid: cooked.pid, | ||
173 | Execve: make([]Exec, 0), | ||
174 | Children: make([]int, 0), | ||
175 | } | ||
176 | process.Execve = append(process.Execve, Exec{ | ||
177 | Timestamp: cooked.timestamp, | ||
178 | ExecArgs: cooked.argv, | ||
179 | }) | ||
180 | |||
181 | err := pidCol.InsertOne(process) | ||
182 | if err != nil { | ||
183 | fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err) | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | func fileOpen(cooked Event) { | ||
189 | // 权限检查过了,不必再查 | ||
190 | file := File{ | ||
191 | OpenTimestamp: cooked.timestamp, | ||
192 | FileName: cooked.srcPath, | ||
193 | Pid: cooked.pid, | ||
194 | Fd: cooked.exit_code, | ||
195 | Flags: cooked.syscallParam, | ||
196 | Written: make([]time.Time, 0), | ||
197 | } | ||
198 | if cooked.syscallParam[1]&syscall.O_TRUNC != 0 { | ||
199 | // 文件以清空方式打开 | ||
200 | file.Written = append(file.Written, cooked.timestamp) | ||
201 | } | ||
202 | |||
203 | err := fdCol.InsertOne(file) | ||
204 | if err != nil { | ||
205 | fmt.Fprintf(os.Stderr, "Err inserting: %v\n", err) | ||
206 | } | ||
207 | } | ||
208 | |||
209 | func fileClose(cooked Event) { | ||
210 | res, err := fdCol.FindOneAndDelete(bson.M{"pid": cooked.pid, "fd": cooked.syscallParam[0]}) | ||
211 | if err != nil { | ||
212 | return | ||
213 | } | ||
214 | res["close_timestamp"] = cooked.timestamp | ||
215 | |||
216 | err = fileCol.InsertOne(res) | ||
217 | if err != nil { | ||
218 | fmt.Fprintf(os.Stderr, "Err inserting files: %v\n", err) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | func fileWrite(cooked Event) { | ||
223 | var res []File | ||
224 | err := fdCol.Finddoc(bson.M{ | ||
225 | "pid": cooked.pid, | ||
226 | "fd": cooked.syscallParam[0], | ||
227 | }, &res) | ||
228 | if err != nil { | ||
229 | fmt.Fprintf(os.Stderr, "Err closing fd %d of pid %d: %v\n", cooked.syscallParam[0], cooked.pid, err) | ||
230 | } | ||
231 | if len(res) == 0 { | ||
232 | return | ||
233 | } | ||
234 | |||
235 | err = fdCol.UpdateOne(bson.M{ | ||
236 | "pid": cooked.pid, | ||
237 | "fd": cooked.syscallParam[0], | ||
238 | }, bson.M{"$push": bson.M{"written": cooked.timestamp}}) | ||
239 | if err != nil { | ||
240 | fmt.Fprintf(os.Stderr, "Err updating: %v\n", err) | ||
241 | } | ||
242 | } | ||
243 | |||
244 | func pivotRoot(cooked Event) { | ||
245 | var docRes []Process | ||
246 | // docker的根目录信息,记录 | ||
247 | err := pidCol.Finddoc(bson.M{"pid": cooked.pid}, &docRes) | ||
248 | if err != nil { | ||
249 | fmt.Fprintf(os.Stderr, "Err finding: %v\n", err) | ||
250 | return | ||
251 | } | ||
252 | |||
253 | if len(docRes) == 0 { | ||
254 | // fork还没到,等一下 | ||
255 | pidCol.InsertOne(bson.M{ | ||
256 | "start_timestamp": cooked.timestamp, | ||
257 | "ppid": cooked.ppid, | ||
258 | "pid": cooked.pid, | ||
259 | "rootfs": "cwd", | ||
260 | }) | ||
261 | } else { | ||
262 | // 读取已有的工作目录 | ||
263 | pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{ | ||
264 | "$set": bson.M{ | ||
265 | "rootfs": docRes[0].Cwd, | ||
266 | }, | ||
267 | }) | ||
268 | } | ||
269 | } | ||
diff --git a/listener/global.go b/listener/global.go new file mode 100644 index 0000000..11b18bf --- /dev/null +++ b/listener/global.go | |||
@@ -0,0 +1,84 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "sync" | ||
5 | "time" | ||
6 | ) | ||
7 | |||
8 | type eventType int | ||
9 | |||
10 | const ( | ||
11 | NEWPID eventType = iota | ||
12 | PIDEXIT | ||
13 | EXECVE | ||
14 | FILEOPEN | ||
15 | FILECLOSE | ||
16 | FILEWRITE | ||
17 | PIVOTROOT | ||
18 | TYPENUM | ||
19 | ) | ||
20 | |||
21 | func (et eventType) String() string { | ||
22 | names := []string{"NEWPID", "PIDEXIT", "EXECVE", "FILEOPEN", "FILECLOSE", "FILEWRITE", "PIVOTROOT", "TYPENUM"} | ||
23 | if et < NEWPID || et > TYPENUM { | ||
24 | return "Unknown" | ||
25 | } | ||
26 | return names[et] | ||
27 | } | ||
28 | |||
29 | type Event struct { | ||
30 | tag eventType | ||
31 | timestamp time.Time | ||
32 | pid, tgid int | ||
33 | ppid, parentTgid int | ||
34 | syscall int | ||
35 | syscallParam [4]uint64 | ||
36 | argc int | ||
37 | argv []string | ||
38 | comm string | ||
39 | cwd string | ||
40 | exit_code int | ||
41 | exit_signal int | ||
42 | srcPath string | ||
43 | destPath string | ||
44 | } | ||
45 | |||
46 | var wg sync.WaitGroup // 掌管协程 | ||
47 | var rawChan chan interface{} // 从接收到整理的管道 | ||
48 | var cookedChan chan Event // 整理好的信息的管道 | ||
49 | var syscallTable [500]string //记录一下系统调用 | ||
50 | var containerdPid int | ||
51 | |||
52 | // 插入到数据库的结构 | ||
53 | type Exec struct { | ||
54 | Timestamp time.Time `bson:"timestamp"` | ||
55 | ExecArgs []string `bson:"execArgs"` | ||
56 | } | ||
57 | |||
58 | type Process struct { | ||
59 | Star bool `bson:"star"` | ||
60 | StartTimestamp time.Time `bson:"start_timestamp"` | ||
61 | Ppid int `bson:"ppid"` | ||
62 | ParentTgid int `bson:"parentTgid"` | ||
63 | Pid int `bson:"pid"` | ||
64 | Tgid int `bson:"tgid"` | ||
65 | Args []string `bson:"args"` | ||
66 | Comm string `bson:"comm"` | ||
67 | RootFS string `bson:"rootfs"` | ||
68 | Cwd string `bson:"cwd"` | ||
69 | Children []int `bson:"children"` | ||
70 | Execve []Exec `bson:"execve"` | ||
71 | ExitCode int `bson:"exit_code"` | ||
72 | ExitSignal int `bson:"exit_signal"` | ||
73 | ExitTimestamp time.Time `bson:"exit_timestamp"` | ||
74 | } | ||
75 | |||
76 | type File struct { | ||
77 | OpenTimestamp time.Time `bson:"timestamp"` | ||
78 | FileName string `bson:"fileName"` | ||
79 | Pid int `bson:"pid"` | ||
80 | Fd int `bson:"fd"` | ||
81 | Flags [4]uint64 `bson:"flags"` | ||
82 | Written []time.Time `bson:"written"` | ||
83 | CloseTimestamp time.Time `bson:"close_timestamp"` | ||
84 | } | ||
diff --git a/listener/go.mod b/listener/go.mod new file mode 100644 index 0000000..ed40331 --- /dev/null +++ b/listener/go.mod | |||
@@ -0,0 +1,26 @@ | |||
1 | module godo | ||
2 | |||
3 | go 1.21.5 | ||
4 | |||
5 | require ( | ||
6 | github.com/elastic/go-libaudit/v2 v2.5.0 | ||
7 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 | ||
8 | go.mongodb.org/mongo-driver v1.16.0 | ||
9 | ) | ||
10 | |||
11 | require ( | ||
12 | github.com/golang/snappy v0.0.4 // indirect | ||
13 | github.com/klauspost/compress v1.13.6 // indirect | ||
14 | github.com/montanaflynn/stats v0.7.1 // indirect | ||
15 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect | ||
16 | github.com/xdg-go/scram v1.1.2 // indirect | ||
17 | github.com/xdg-go/stringprep v1.0.4 // indirect | ||
18 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect | ||
19 | go.uber.org/atomic v1.7.0 // indirect | ||
20 | go.uber.org/multierr v1.7.0 // indirect | ||
21 | golang.org/x/crypto v0.22.0 // indirect | ||
22 | golang.org/x/sync v0.7.0 // indirect | ||
23 | golang.org/x/sys v0.19.0 // indirect | ||
24 | golang.org/x/text v0.14.0 // indirect | ||
25 | gopkg.in/yaml.v3 v3.0.1 // indirect | ||
26 | ) | ||
diff --git a/listener/go.sum b/listener/go.sum new file mode 100644 index 0000000..9164cd3 --- /dev/null +++ b/listener/go.sum | |||
@@ -0,0 +1,96 @@ | |||
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
4 | github.com/elastic/go-libaudit/v2 v2.5.0 h1:5OK919QRnGtcjVBz3n/cs5F42im1mPlVTA9TyIn2K54= | ||
5 | github.com/elastic/go-libaudit/v2 v2.5.0/go.mod h1:AjlnhinP+kKQuUJoXLVrqxBM8uyhQmkzoV6jjsCFP4Q= | ||
6 | github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4= | ||
7 | github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU= | ||
8 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= | ||
9 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | ||
10 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | ||
11 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
12 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= | ||
13 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= | ||
14 | github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= | ||
15 | github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= | ||
16 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= | ||
17 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= | ||
18 | github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= | ||
19 | github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | ||
20 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
21 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
22 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
23 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
24 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
25 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
26 | github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= | ||
27 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= | ||
28 | github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= | ||
29 | github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= | ||
30 | github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= | ||
31 | github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= | ||
32 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= | ||
33 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | ||
34 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||
35 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
36 | go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4= | ||
37 | go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= | ||
38 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= | ||
39 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= | ||
40 | go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= | ||
41 | go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= | ||
42 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
43 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
44 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
45 | golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= | ||
46 | golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= | ||
47 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= | ||
48 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | ||
49 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||
50 | golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= | ||
51 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
52 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
53 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
54 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
55 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||
56 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
57 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
58 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
59 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
60 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= | ||
61 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||
62 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
63 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
64 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
65 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
66 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
67 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
68 | golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
69 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
70 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
71 | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
72 | golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= | ||
73 | golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||
74 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
75 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
76 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
77 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
78 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
79 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
80 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= | ||
81 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | ||
82 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | ||
83 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
84 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
85 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||
86 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= | ||
87 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
88 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
89 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
90 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
91 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
92 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||
93 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
94 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
95 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
96 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
diff --git a/listener/go.work b/listener/go.work new file mode 100644 index 0000000..5b6c957 --- /dev/null +++ b/listener/go.work | |||
@@ -0,0 +1,6 @@ | |||
1 | go 1.21.5 | ||
2 | |||
3 | use ( | ||
4 | ./netlink | ||
5 | ./ | ||
6 | ) \ No newline at end of file | ||
diff --git a/listener/go.work.sum b/listener/go.work.sum new file mode 100644 index 0000000..8201e39 --- /dev/null +++ b/listener/go.work.sum | |||
@@ -0,0 +1,4 @@ | |||
1 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
2 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= | ||
3 | golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= | ||
4 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||
diff --git a/listener/godo.go b/listener/godo.go new file mode 100644 index 0000000..efe9585 --- /dev/null +++ b/listener/godo.go | |||
@@ -0,0 +1,176 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "flag" | ||
6 | "fmt" | ||
7 | "log" | ||
8 | "netlink" | ||
9 | "os" | ||
10 | "os/exec" | ||
11 | "strings" | ||
12 | "syscall" | ||
13 | "time" | ||
14 | |||
15 | "github.com/elastic/go-libaudit/v2" | ||
16 | ) | ||
17 | |||
18 | var ( | ||
19 | fs = flag.NewFlagSet("audit", flag.ExitOnError) | ||
20 | diag = fs.String("diag", "", "dump raw information from kernel to file") | ||
21 | rate = fs.Uint("rate", 0, "rate limit in kernel (default 0, no rate limit)") | ||
22 | backlog = fs.Uint("backlog", 8192, "backlog limit") | ||
23 | immutable = fs.Bool("immutable", false, "make kernel audit settings immutable (requires reboot to undo)") | ||
24 | receiveOnly = fs.Bool("ro", false, "receive only using multicast, requires kernel 3.16+") | ||
25 | ) | ||
26 | |||
27 | func main() { | ||
28 | // 检查用户身份,并添加auditd规则,监听所有syscall | ||
29 | if os.Geteuid() != 0 { | ||
30 | fmt.Fprintf(os.Stderr, "Err: Please run me as root, %d!\n", os.Getegid()) | ||
31 | return | ||
32 | } | ||
33 | |||
34 | // 所有的系统调用号与名称的关系 | ||
35 | err := figureOutSyscalls() | ||
36 | if err != nil { | ||
37 | fmt.Fprintf(os.Stderr, "Error figuring out syscall numbers: %v\n", err) | ||
38 | } | ||
39 | |||
40 | exec.Command("auditctl", "-D").Run() | ||
41 | exec.Command("auditctl", "-b", "1000000000").Run() | ||
42 | exec.Command("auditctl", "--reset-lost").Run() | ||
43 | |||
44 | var auditCmd *exec.Cmd | ||
45 | |||
46 | pidSyscall := []string{"execve", "pivot_root"} | ||
47 | // // 设置监听规则 | ||
48 | for i := 0; i < len(pidSyscall); i++ { | ||
49 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", pidSyscall[i]) | ||
50 | auditCmd.Run() | ||
51 | } | ||
52 | |||
53 | // 监听文件的消息 | ||
54 | fileSyscall := []string{"open", "close", "write"} | ||
55 | // fileSyscall := []string{"open", "write", "creat", "unlink", "opendir", "mkdir", "rmdir", "chmod", "fchmod", "chown", "fchown", "lchown", "flock"} | ||
56 | for i := 0; i < len(fileSyscall); i++ { | ||
57 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", fileSyscall[i]) | ||
58 | auditCmd.Run() | ||
59 | } | ||
60 | |||
61 | // 查找pid | ||
62 | containerdPid, err = getPid() | ||
63 | if err != nil { | ||
64 | fmt.Fprintf(os.Stderr, "Error finding containerd: %v\n", err) | ||
65 | return | ||
66 | } | ||
67 | |||
68 | // 开始运行,解析命令行参数后监听 | ||
69 | if err := fs.Parse(os.Args[1:]); err != nil { | ||
70 | log.Fatal(err) | ||
71 | } | ||
72 | |||
73 | if err := read(); err != nil { | ||
74 | log.Fatalf("error: %v", err) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | func coroutine(client *libaudit.AuditClient) { | ||
79 | // 各协程至此开始 | ||
80 | rawChan = make(chan interface{}, 65536) | ||
81 | cookedChan = make(chan Event, 65536) | ||
82 | |||
83 | wg.Add(1) | ||
84 | go procWatch() | ||
85 | |||
86 | wg.Add(1) | ||
87 | go receive(client) | ||
88 | wg.Add(1) | ||
89 | go orgnaze() | ||
90 | wg.Add(1) | ||
91 | go deal() | ||
92 | |||
93 | wg.Wait() | ||
94 | time.Sleep(2 * time.Second) | ||
95 | } | ||
96 | |||
97 | func procWatch() error { | ||
98 | ns, err := netlink.NewNetlinkSocket(syscall.NETLINK_CONNECTOR, 12345) | ||
99 | if err != nil { | ||
100 | fmt.Fprintf(os.Stderr, "Error creating socket: %v\n", err) | ||
101 | return err | ||
102 | } | ||
103 | defer ns.Close() | ||
104 | for { | ||
105 | res, err := ns.Receive(20) | ||
106 | if err != nil { | ||
107 | fmt.Fprintf(os.Stderr, "Error recv: %v\n", err) | ||
108 | continue | ||
109 | } | ||
110 | for i := 0; i < len(res); i++ { | ||
111 | procEvent := netlink.ParseProcEvent(res[i].Data) | ||
112 | switch procEvent.What { | ||
113 | case netlink.PROC_EVENT_FORK: | ||
114 | data := procEvent.Data.(netlink.ProcEventFork) | ||
115 | cooked := Event{ | ||
116 | tag: NEWPID, | ||
117 | timestamp: time.Now(), | ||
118 | pid: int(data.ChildPid), | ||
119 | tgid: int(data.ChildTgid), | ||
120 | ppid: int(data.ParentPid), | ||
121 | parentTgid: int(data.ParentTgid), | ||
122 | } | ||
123 | checkProc(&cooked) | ||
124 | cookedChan <- cooked | ||
125 | case netlink.PROC_EVENT_EXIT: | ||
126 | data := procEvent.Data.(netlink.ProcEventExit) | ||
127 | cooked := Event{ | ||
128 | tag: PIDEXIT, | ||
129 | timestamp: time.Now(), | ||
130 | pid: int(data.ProcessPid), | ||
131 | exit_code: int(data.ExitCode), | ||
132 | exit_signal: int(data.ExitSignal), | ||
133 | } | ||
134 | cookedChan <- cooked | ||
135 | default: | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | func checkProc(pCooked *Event) { | ||
142 | fileName := fmt.Sprintf("/proc/%d/task/%d/", pCooked.tgid, pCooked.pid) | ||
143 | fd, err := os.Open(fileName + "cmdline") | ||
144 | if err != nil { | ||
145 | fmt.Fprintf(os.Stderr, "Err: %v\n", err) | ||
146 | return | ||
147 | } | ||
148 | |||
149 | scanner := bufio.NewScanner(fd) | ||
150 | scanner.Split(bufio.ScanLines) | ||
151 | for scanner.Scan() { | ||
152 | line := scanner.Text() | ||
153 | pCooked.argv = append(pCooked.argv, strings.Split(line, "\x00")...) | ||
154 | } | ||
155 | pCooked.argc = len(pCooked.argv) | ||
156 | fd.Close() | ||
157 | |||
158 | fd, err = os.Open(fileName + "comm") | ||
159 | if err != nil { | ||
160 | fmt.Fprintf(os.Stderr, "Err: %v\n", err) | ||
161 | return | ||
162 | } | ||
163 | scanner = bufio.NewScanner(fd) | ||
164 | scanner.Split(bufio.ScanLines) | ||
165 | for scanner.Scan() { | ||
166 | line := scanner.Text() | ||
167 | pCooked.comm = line | ||
168 | } | ||
169 | fd.Close() | ||
170 | |||
171 | pCooked.cwd, err = os.Readlink(fileName + "cwd") | ||
172 | if err != nil { | ||
173 | fmt.Fprintf(os.Stderr, "Err: %v\n", err) | ||
174 | pCooked.cwd = "" | ||
175 | } | ||
176 | } | ||
diff --git a/listener/mongo.go b/listener/mongo.go new file mode 100644 index 0000000..a51350e --- /dev/null +++ b/listener/mongo.go | |||
@@ -0,0 +1,122 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "context" | ||
5 | "fmt" | ||
6 | "reflect" | ||
7 | "time" | ||
8 | |||
9 | "go.mongodb.org/mongo-driver/bson" | ||
10 | "go.mongodb.org/mongo-driver/mongo" | ||
11 | "go.mongodb.org/mongo-driver/mongo/options" | ||
12 | ) | ||
13 | |||
14 | type mongoClient struct { | ||
15 | dbName, colName string | ||
16 | client *mongo.Client | ||
17 | col *mongo.Collection | ||
18 | } | ||
19 | |||
20 | func (mc *mongoClient) init(dbName, colName string) error { | ||
21 | var err error | ||
22 | if err = mc.Connect(dbName, colName); err != nil { | ||
23 | return err | ||
24 | } | ||
25 | if err = mc.Drop(); err != nil { | ||
26 | return err | ||
27 | } | ||
28 | |||
29 | return nil | ||
30 | } | ||
31 | |||
32 | func (mc *mongoClient) Connect(dbName, colName string) error { | ||
33 | var err error | ||
34 | mc.client, err = mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017")) | ||
35 | |||
36 | if err != nil { | ||
37 | return err | ||
38 | } | ||
39 | |||
40 | ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||
41 | err = mc.client.Connect(ctx) | ||
42 | if err != nil { | ||
43 | return err | ||
44 | } | ||
45 | |||
46 | mc.col = mc.client.Database(dbName).Collection(colName) | ||
47 | mc.dbName = dbName | ||
48 | mc.colName = colName | ||
49 | return nil | ||
50 | } | ||
51 | |||
52 | func (mc *mongoClient) InsertOne(document interface{}) error { | ||
53 | _, err := mc.col.InsertOne(context.Background(), document) | ||
54 | return err | ||
55 | } | ||
56 | |||
57 | func (mc *mongoClient) UpdateOne(filter, update interface{}) error { | ||
58 | _, err := mc.col.UpdateOne(context.Background(), filter, update) | ||
59 | return err | ||
60 | } | ||
61 | |||
62 | func (mc *mongoClient) UpdateMany(filter, update interface{}) error { | ||
63 | _, err := mc.col.UpdateMany(context.Background(), filter, update) | ||
64 | return err | ||
65 | } | ||
66 | |||
67 | func (mc *mongoClient) ReplaceOne(filter, new interface{}) error { | ||
68 | _, err := mc.col.ReplaceOne(context.Background(), filter, new) | ||
69 | return err | ||
70 | } | ||
71 | |||
72 | func (mc *mongoClient) Finddoc(filter bson.M, results interface{}) error { | ||
73 | sliceValue := reflect.ValueOf(results) | ||
74 | |||
75 | if sliceValue.Kind() != reflect.Ptr || sliceValue.Elem().Kind() != reflect.Slice { | ||
76 | return fmt.Errorf("Error: result argument must be pointer to slice") | ||
77 | } | ||
78 | cur, err := mc.col.Find(context.TODO(), filter) | ||
79 | if err != nil { | ||
80 | return err | ||
81 | } | ||
82 | defer cur.Close(context.TODO()) | ||
83 | |||
84 | elemType := sliceValue.Elem().Type().Elem() | ||
85 | |||
86 | sliceValue = sliceValue.Elem() | ||
87 | |||
88 | for cur.Next(context.TODO()) { | ||
89 | elem := reflect.New(elemType).Interface() | ||
90 | err := cur.Decode(elem) | ||
91 | if err != nil { | ||
92 | return err | ||
93 | } | ||
94 | sliceValue = reflect.Append(sliceValue, reflect.ValueOf(elem).Elem()) | ||
95 | } | ||
96 | |||
97 | reflect.ValueOf(results).Elem().Set(sliceValue) | ||
98 | return nil | ||
99 | } | ||
100 | |||
101 | func (mc *mongoClient) FindOneAndDelete(filter bson.M) (bson.M, error) { | ||
102 | res := mc.col.FindOneAndDelete(context.Background(), filter) | ||
103 | var result bson.M | ||
104 | err := res.Decode(&result) | ||
105 | return result, err | ||
106 | } | ||
107 | |||
108 | func (mc *mongoClient) Drop() error { | ||
109 | return mc.col.Drop(context.Background()) | ||
110 | } | ||
111 | |||
112 | func (mc *mongoClient) Disconnect() error { | ||
113 | err := mc.client.Disconnect(context.Background()) | ||
114 | if err != nil { | ||
115 | return err | ||
116 | } | ||
117 | mc.col = nil | ||
118 | mc.client = nil | ||
119 | mc.dbName = "" | ||
120 | mc.colName = "" | ||
121 | return nil | ||
122 | } | ||
diff --git a/listener/netlink b/listener/netlink new file mode 160000 | |||
Subproject e53c2724725c5991cdd9ea088c26832c5c9fcf0 | |||
diff --git a/listener/organize.go b/listener/organize.go new file mode 100644 index 0000000..0c05eb4 --- /dev/null +++ b/listener/organize.go | |||
@@ -0,0 +1,291 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "os" | ||
6 | "regexp" | ||
7 | "strconv" | ||
8 | "strings" | ||
9 | "sync" | ||
10 | "syscall" | ||
11 | |||
12 | "github.com/elastic/go-libaudit/v2" | ||
13 | "github.com/elastic/go-libaudit/v2/auparse" | ||
14 | ) | ||
15 | |||
16 | // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的 | ||
17 | var eventTable sync.Map | ||
18 | |||
19 | // 事件信息 | ||
20 | var tmp any | ||
21 | var ok bool | ||
22 | var event Event | ||
23 | var pEvent *Event | ||
24 | var eventId, argc int | ||
25 | |||
26 | // 要用的正则匹配列表 | ||
27 | var ( | ||
28 | syscallRegex = regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+)(?:.*?exit=([-+]?\d+))?.*?ppid=(\d+) pid=(\d+).*?subj=(.*?):(.*?):(.*?):(.*?) .*?$`) | ||
29 | execveRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`) | ||
30 | argsRegex = regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`) | ||
31 | pathRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): item=(\d+) name="(.*?)" .*objtype=([A-Z]+) `) | ||
32 | cwdRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`) | ||
33 | proctitleRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`) | ||
34 | eoeRegex = regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`) | ||
35 | ) | ||
36 | |||
37 | func orgnaze() { | ||
38 | defer wg.Done() | ||
39 | defer close(cookedChan) | ||
40 | // 接收信息 | ||
41 | var raw interface{} | ||
42 | var rawEvent libaudit.RawAuditMessage | ||
43 | |||
44 | for { | ||
45 | raw, ok = <-rawChan | ||
46 | if !ok { | ||
47 | break | ||
48 | } | ||
49 | rawEvent = raw.(libaudit.RawAuditMessage) | ||
50 | // fmt.Printf("type=%v msg=%s\n", rawEvent.Type, rawEvent.Data) | ||
51 | |||
52 | switch rawEvent.Type { | ||
53 | case auparse.AUDIT_SYSCALL: | ||
54 | syscallRaw(rawEvent) | ||
55 | case auparse.AUDIT_EXECVE: | ||
56 | execve(rawEvent) | ||
57 | case auparse.AUDIT_CWD: | ||
58 | cwd(rawEvent) | ||
59 | case auparse.AUDIT_PATH: | ||
60 | path(rawEvent) | ||
61 | case auparse.AUDIT_PROCTITLE: | ||
62 | proctitle(rawEvent) | ||
63 | case auparse.AUDIT_EOE: | ||
64 | eoe(rawEvent) | ||
65 | default: | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | func syscallRaw(rawEvent libaudit.RawAuditMessage) { | ||
71 | if !syscallRegex.Match(rawEvent.Data) { | ||
72 | return | ||
73 | } | ||
74 | |||
75 | var exit int | ||
76 | var a [4]uint64 | ||
77 | var subj [4]string | ||
78 | // 捕获基础信息 | ||
79 | match := syscallRegex.FindSubmatch(rawEvent.Data) | ||
80 | event.timestamp, _ = getTimeFromStr(string(match[1])) | ||
81 | eventId, _ = strconv.Atoi(string(match[2])) | ||
82 | event.syscall, _ = strconv.Atoi(string(match[3])) | ||
83 | if string(match[4]) == "" { | ||
84 | // exit没捕获到 | ||
85 | exit = 0 | ||
86 | } else { | ||
87 | exit, _ = strconv.Atoi(string(match[4])) | ||
88 | } | ||
89 | event.ppid, _ = strconv.Atoi(string(match[5])) | ||
90 | event.pid, _ = strconv.Atoi(string(match[6])) | ||
91 | |||
92 | // 几个subj,说不定会有用 | ||
93 | for i := 0; i < 4; i++ { | ||
94 | subj[i] = string(match[7+i]) | ||
95 | } | ||
96 | |||
97 | // 捕获参数 | ||
98 | if !argsRegex.Match(rawEvent.Data) { | ||
99 | fmt.Fprintf(os.Stderr, "Error: don't get args in syscall event!\n") | ||
100 | return | ||
101 | } | ||
102 | argsMatch := argsRegex.FindAllSubmatch(rawEvent.Data, -1) | ||
103 | for i := 0; i < 4; i++ { | ||
104 | a[i], _ = strconv.ParseUint(string(argsMatch[i][3]), 16, 64) | ||
105 | } | ||
106 | |||
107 | switch syscallTable[event.syscall] { | ||
108 | case "execve": | ||
109 | eventTable.Store(eventId, &Event{ | ||
110 | tag: EXECVE, | ||
111 | timestamp: event.timestamp, | ||
112 | syscall: event.syscall, | ||
113 | // exit_code: a[0], // 为啥这么写? | ||
114 | ppid: event.ppid, | ||
115 | pid: event.pid, | ||
116 | argc: 0, | ||
117 | argv: make([]string, 0), | ||
118 | cwd: "", | ||
119 | }) | ||
120 | case "open": | ||
121 | // 检查打开的权限 | ||
122 | if a[1]&(syscall.O_APPEND|syscall.O_WRONLY|syscall.O_RDWR|syscall.O_TRUNC) == 0 { | ||
123 | break | ||
124 | } | ||
125 | // TRUNC应该被直接标记为改变,而不是打开 | ||
126 | eventTable.Store(eventId, &Event{ | ||
127 | tag: FILEOPEN, | ||
128 | timestamp: event.timestamp, | ||
129 | syscall: event.syscall, | ||
130 | exit_code: exit, | ||
131 | ppid: event.ppid, | ||
132 | pid: event.pid, | ||
133 | argc: 0, | ||
134 | argv: make([]string, 0), | ||
135 | cwd: "", | ||
136 | syscallParam: a, | ||
137 | srcPath: "", | ||
138 | }) | ||
139 | case "write": | ||
140 | eventTable.Store(eventId, &Event{ | ||
141 | tag: FILEWRITE, | ||
142 | timestamp: event.timestamp, | ||
143 | syscall: event.syscall, | ||
144 | exit_code: exit, | ||
145 | ppid: event.ppid, | ||
146 | pid: event.pid, | ||
147 | argc: 0, | ||
148 | argv: make([]string, 0), | ||
149 | cwd: "", | ||
150 | syscallParam: a, | ||
151 | }) | ||
152 | case "close": | ||
153 | // 文件关闭 | ||
154 | eventTable.Store(eventId, &Event{ | ||
155 | tag: FILECLOSE, | ||
156 | timestamp: event.timestamp, | ||
157 | syscall: event.syscall, | ||
158 | exit_code: exit, | ||
159 | ppid: event.ppid, | ||
160 | pid: event.pid, | ||
161 | argc: 0, | ||
162 | argv: make([]string, 0), | ||
163 | cwd: "", | ||
164 | syscallParam: a, | ||
165 | }) | ||
166 | case "pivot_root": | ||
167 | if subj[2] == "container_runtime_t" { | ||
168 | eventTable.Store(eventId, &Event{ | ||
169 | tag: PIVOTROOT, | ||
170 | timestamp: event.timestamp, | ||
171 | syscall: event.syscall, | ||
172 | ppid: event.ppid, | ||
173 | pid: event.pid, | ||
174 | syscallParam: a, | ||
175 | }) | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | func execve(rawEvent libaudit.RawAuditMessage) { | ||
181 | if !execveRegex.Match(rawEvent.Data) { | ||
182 | return | ||
183 | } | ||
184 | |||
185 | match := execveRegex.FindSubmatch(rawEvent.Data) | ||
186 | eventId, _ = strconv.Atoi(string(match[1])) | ||
187 | argc, _ = strconv.Atoi(string(match[2])) | ||
188 | tmp, ok = eventTable.Load(eventId) | ||
189 | if !ok { | ||
190 | return | ||
191 | } | ||
192 | pEvent = tmp.(*Event) | ||
193 | if argsRegex.Match(rawEvent.Data) { | ||
194 | match := argsRegex.FindAllSubmatch(rawEvent.Data, -1) | ||
195 | for i := 0; i < argc; i++ { | ||
196 | if len(match[i][2]) == 0 { | ||
197 | // 代表着匹配到的是十六进制数 | ||
198 | str := hexToAscii(string(match[i][3])) | ||
199 | pEvent.argv = append(pEvent.argv, str) | ||
200 | } else { | ||
201 | pEvent.argv = append(pEvent.argv, string(match[i][2])) | ||
202 | } | ||
203 | } | ||
204 | pEvent.argc = argc | ||
205 | } | ||
206 | } | ||
207 | |||
208 | func cwd(rawEvent libaudit.RawAuditMessage) { | ||
209 | if !cwdRegex.Match(rawEvent.Data) { | ||
210 | return | ||
211 | } | ||
212 | |||
213 | match := cwdRegex.FindSubmatch(rawEvent.Data) | ||
214 | eventId, _ = strconv.Atoi(string(match[1])) | ||
215 | tmp, ok = eventTable.Load(eventId) | ||
216 | if !ok { | ||
217 | return | ||
218 | } | ||
219 | tmp.(*Event).cwd = string(match[2]) | ||
220 | } | ||
221 | |||
222 | func proctitle(rawEvent libaudit.RawAuditMessage) { | ||
223 | if !proctitleRegex.Match(rawEvent.Data) { | ||
224 | return | ||
225 | } | ||
226 | |||
227 | var cmdline string | ||
228 | match := proctitleRegex.FindSubmatch(rawEvent.Data) | ||
229 | eventId, _ = strconv.Atoi(string(match[1])) | ||
230 | tmp, ok = eventTable.Load(eventId) | ||
231 | if !ok { | ||
232 | return | ||
233 | } | ||
234 | pEvent = tmp.(*Event) | ||
235 | if pEvent.argc == 0 { | ||
236 | // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数 | ||
237 | if match[3] == nil { | ||
238 | // PROCTITLE写的是十六进制,转换为字符串 | ||
239 | cmdline = hexToAscii(string(match[4])) | ||
240 | } else { | ||
241 | cmdline = string(match[3]) | ||
242 | } | ||
243 | pEvent.argv = strings.Split(cmdline, " ") | ||
244 | pEvent.argc = len(pEvent.argv) | ||
245 | } | ||
246 | } | ||
247 | |||
248 | func eoe(rawEvent libaudit.RawAuditMessage) { | ||
249 | if !eoeRegex.Match(rawEvent.Data) { | ||
250 | return | ||
251 | } | ||
252 | |||
253 | match := eoeRegex.FindSubmatch(rawEvent.Data) | ||
254 | eventId, _ = strconv.Atoi(string(match[1])) | ||
255 | tmp, ok = eventTable.Load(eventId) | ||
256 | if !ok { | ||
257 | return | ||
258 | } | ||
259 | cooked := *(tmp.(*Event)) | ||
260 | cookedChan <- cooked | ||
261 | eventTable.Delete(eventId) // 死人别占地 | ||
262 | } | ||
263 | |||
264 | func path(rawEvent libaudit.RawAuditMessage) { | ||
265 | if !pathRegex.Match(rawEvent.Data) { | ||
266 | return | ||
267 | } | ||
268 | match := pathRegex.FindSubmatch(rawEvent.Data) | ||
269 | eventId, _ = strconv.Atoi(string(match[1])) | ||
270 | // item, _ := strconv.Atoi(string(match[2])) | ||
271 | name := string(match[3]) | ||
272 | objtype := string(match[4]) | ||
273 | |||
274 | tmp, ok = eventTable.Load(eventId) | ||
275 | if !ok { | ||
276 | return | ||
277 | } | ||
278 | pEvent = tmp.(*Event) | ||
279 | |||
280 | // 先看看是不是文件操作,再看是不是所在目录 | ||
281 | if pEvent.tag != FILEOPEN || objtype == "PARENT" { | ||
282 | return | ||
283 | } | ||
284 | |||
285 | if pEvent.cwd == "/" || name[0] == '/' { | ||
286 | pEvent.srcPath = name | ||
287 | } else { | ||
288 | pEvent.srcPath = pEvent.cwd + "/" + name | ||
289 | } | ||
290 | // ATTENTION: 这里需要做路径简化,留给过滤清洗流程吧 | ||
291 | } | ||
diff --git a/listener/receive.go b/listener/receive.go new file mode 100644 index 0000000..c0dea00 --- /dev/null +++ b/listener/receive.go | |||
@@ -0,0 +1,29 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
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 | |||
11 | func 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 | } | ||