diff options
author | We-unite <3205135446@qq.com> | 2024-07-17 11:47:03 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-07-17 14:03:06 +0800 |
commit | f055b3940f999c2e26448812e67b68da363dcbad (patch) | |
tree | 145411eb93d96ecd4b5b24783d10da5e345791f7 /old/auparse.go | |
download | godo-f055b3940f999c2e26448812e67b68da363dcbad.tar.gz godo-f055b3940f999c2e26448812e67b68da363dcbad.zip |
Initial commit
This repo is to supervise all processes in containers, in other
words inspect behaviors of dockers, and get the pid tree.
There are several ways for programs in user space to intereact with
kernel space:
- system calls, which can be found out in source path arch/x86/syscalls
- ioctl
- /proc virtual file system, to read kernel realtime info
- nerlink socket
the pid we should pay attention to is /usr/bin/containerd, which may
come from service docker-daemon and ppid is 1. Each time a docker is
start or stop, this forks a pid, the pid then forks, that's the main
process of the docker.
To grub the info of pid create or exit, this program is based on
go-libauditd, which uses netlink socket to hear from kernel about
audit log. What's worrying is that one event is always devided into
several entries, and several events may be received alternately.
So, from my point of view, which program has 3 coroutines and 2
channels. the first receives raw event message from audit, then
throw it to channel 1; the second listen to channel 1, and organizes
each event until there's a EOE, then throw to channel 2; the third
discover event from channel 2, deal with th event, such as create or
delete pid. Specially, since two relative infomation(pid 1 fork pid2,
then pid 1 exits)may comes out of order, deletion mast be delayed for
some time(may 1 second), to keep the process tree correct.
Diffstat (limited to 'old/auparse.go')
-rw-r--r-- | old/auparse.go | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/old/auparse.go b/old/auparse.go new file mode 100644 index 0000000..53b0c92 --- /dev/null +++ b/old/auparse.go | |||
@@ -0,0 +1,218 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "encoding/json" | ||
6 | "flag" | ||
7 | "fmt" | ||
8 | "io" | ||
9 | "log" | ||
10 | "os" | ||
11 | "time" | ||
12 | |||
13 | "gopkg.in/yaml.v3" | ||
14 | |||
15 | "github.com/elastic/go-libaudit/v2" | ||
16 | "github.com/elastic/go-libaudit/v2/aucoalesce" | ||
17 | "github.com/elastic/go-libaudit/v2/auparse" | ||
18 | ) | ||
19 | |||
20 | var ( | ||
21 | fs = flag.NewFlagSet("auparse", flag.ExitOnError) | ||
22 | in = fs.String("in", "-", "input file (defaults to stdin)") | ||
23 | out = fs.String("out", "-", "output file (defaults to stdout)") | ||
24 | interpret = fs.Bool("i", false, "interpret and normalize messages") | ||
25 | idLookup = fs.Bool("id", true, "lookup uid and gid values in messages (requires -i)") | ||
26 | format = fs.String("format", "", "output format, possible values - json, yaml, text (default)") | ||
27 | ) | ||
28 | |||
29 | func main() { | ||
30 | if err := fs.Parse(os.Args[1:]); err != nil { | ||
31 | log.Fatal(err) | ||
32 | } | ||
33 | |||
34 | if err := processLogs(); err != nil { | ||
35 | log.Fatalf("error: %v", err) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | func input() (io.ReadCloser, error) { | ||
40 | if *in == "-" { | ||
41 | return os.Stdin, nil | ||
42 | } | ||
43 | |||
44 | return os.Open(*in) | ||
45 | } | ||
46 | |||
47 | func output() (io.WriteCloser, error) { | ||
48 | if *out == "-" { | ||
49 | return os.Stdout, nil | ||
50 | } | ||
51 | |||
52 | return os.OpenFile(*out, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o600) | ||
53 | } | ||
54 | |||
55 | func processLogs() error { | ||
56 | input, err := input() | ||
57 | if err != nil { | ||
58 | return err | ||
59 | } | ||
60 | defer input.Close() | ||
61 | |||
62 | output, err := output() | ||
63 | if err != nil { | ||
64 | return err | ||
65 | } | ||
66 | defer output.Close() | ||
67 | |||
68 | reassembler, err := libaudit.NewReassembler(5, 2*time.Second, &streamHandler{output}) | ||
69 | if err != nil { | ||
70 | return fmt.Errorf("failed to create reassmbler: %w", err) | ||
71 | } | ||
72 | defer reassembler.Close() | ||
73 | |||
74 | // Start goroutine to periodically purge timed-out events. | ||
75 | go func() { | ||
76 | t := time.NewTicker(500 * time.Millisecond) | ||
77 | defer t.Stop() | ||
78 | for range t.C { | ||
79 | if reassembler.Maintain() != nil { | ||
80 | return | ||
81 | } | ||
82 | } | ||
83 | }() | ||
84 | |||
85 | // Process lines from the input. | ||
86 | s := bufio.NewScanner(input) | ||
87 | for s.Scan() { | ||
88 | line := s.Text() | ||
89 | |||
90 | auditMsg, err := auparse.ParseLogLine(line) | ||
91 | if err != nil { | ||
92 | log.Printf("failed to parse message header: %v", err) | ||
93 | } | ||
94 | |||
95 | reassembler.PushMessage(auditMsg) | ||
96 | } | ||
97 | |||
98 | return nil | ||
99 | } | ||
100 | |||
101 | type streamHandler struct { | ||
102 | output io.Writer | ||
103 | } | ||
104 | |||
105 | func (s *streamHandler) ReassemblyComplete(msgs []*auparse.AuditMessage) { | ||
106 | if err := s.outputMultipleMessages(msgs); err != nil { | ||
107 | log.Printf("[WARN] failed writing message to output: %v", err) | ||
108 | } | ||
109 | } | ||
110 | |||
111 | func (*streamHandler) EventsLost(count int) { | ||
112 | log.Printf("detected the loss of %v sequences.", count) | ||
113 | } | ||
114 | |||
115 | func (s *streamHandler) outputMultipleMessages(msgs []*auparse.AuditMessage) error { | ||
116 | var err error | ||
117 | if !*interpret { | ||
118 | if _, err = s.output.Write([]byte("---\n")); err != nil { | ||
119 | return err | ||
120 | } | ||
121 | for _, m := range msgs { | ||
122 | if err = s.outputSingleMessage(m); err != nil { | ||
123 | return err | ||
124 | } | ||
125 | } | ||
126 | return nil | ||
127 | } | ||
128 | |||
129 | event, err := aucoalesce.CoalesceMessages(msgs) | ||
130 | if err != nil { | ||
131 | log.Printf("failed to coalesce messages: %v", err) | ||
132 | return nil | ||
133 | } | ||
134 | |||
135 | if *idLookup { | ||
136 | aucoalesce.ResolveIDs(event) | ||
137 | } | ||
138 | |||
139 | switch *format { | ||
140 | case "json": | ||
141 | if err := s.printJSON(event); err != nil { | ||
142 | log.Printf("failed to marshal event to JSON: %v", err) | ||
143 | } | ||
144 | case "yaml": | ||
145 | if _, err := s.output.Write([]byte("---\n")); err != nil { | ||
146 | return err | ||
147 | } | ||
148 | if err := s.printYAML(event); err != nil { | ||
149 | log.Printf("failed to marshal message to YAML: %v", err) | ||
150 | } | ||
151 | default: | ||
152 | sm := event.Summary | ||
153 | if _, err := s.output.Write([]byte("---\n")); err != nil { | ||
154 | return err | ||
155 | } | ||
156 | |||
157 | _, err := fmt.Fprintf( | ||
158 | s.output, | ||
159 | `time="%v" sequence=%v category=%v type=%v actor=%v/%v action=%v thing=%v/%v how=%v tags=%v`+"\n", | ||
160 | event.Timestamp, event.Sequence, event.Category, event.Type, sm.Actor.Primary, sm.Actor.Secondary, | ||
161 | sm.Action, sm.Object.Primary, sm.Object.Secondary, sm.How, event.Tags, | ||
162 | ) | ||
163 | if err != nil { | ||
164 | return err | ||
165 | } | ||
166 | } | ||
167 | return nil | ||
168 | } | ||
169 | |||
170 | func (s *streamHandler) outputSingleMessage(m *auparse.AuditMessage) error { | ||
171 | switch *format { | ||
172 | case "json": | ||
173 | if err := s.printJSON(m.ToMapStr()); err != nil { | ||
174 | log.Printf("failed to marshal message to JSON: %v", err) | ||
175 | } | ||
176 | case "yaml": | ||
177 | if err := s.printYAML(m.ToMapStr()); err != nil { | ||
178 | log.Printf("failed to marshal message to YAML: %v", err) | ||
179 | } | ||
180 | default: | ||
181 | if _, err := fmt.Fprintf( | ||
182 | s.output, | ||
183 | "type=%v msg=%v\n", | ||
184 | m.RecordType, m.RawData, | ||
185 | ); err != nil { | ||
186 | return err | ||
187 | } | ||
188 | } | ||
189 | return nil | ||
190 | } | ||
191 | |||
192 | func (s *streamHandler) printJSON(v interface{}) error { | ||
193 | jsonBytes, err := json.Marshal(v) | ||
194 | if err != nil { | ||
195 | return err | ||
196 | } | ||
197 | if _, err = s.output.Write(jsonBytes); err != nil { | ||
198 | return err | ||
199 | } | ||
200 | if _, err = s.output.Write([]byte("\n")); err != nil { | ||
201 | return err | ||
202 | } | ||
203 | return nil | ||
204 | } | ||
205 | |||
206 | func (s *streamHandler) printYAML(v interface{}) error { | ||
207 | yamlBytes, err := yaml.Marshal(v) | ||
208 | if err != nil { | ||
209 | return err | ||
210 | } | ||
211 | if _, err = s.output.Write(yamlBytes); err != nil { | ||
212 | return err | ||
213 | } | ||
214 | if _, err = s.output.Write([]byte("\n")); err != nil { | ||
215 | return err | ||
216 | } | ||
217 | return nil | ||
218 | } | ||