Skip to content

Commit a3ab865

Browse files
committed
Initial commit
1 parent 835733e commit a3ab865

File tree

3 files changed

+359
-0
lines changed

3 files changed

+359
-0
lines changed

Makefile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CLANG = clang-9
2+
CFLAGS = -O2 -g -Wall -Werror -Wunused-value
3+
4+
export BPF_CLANG := $(CLANG)
5+
export BPF_CFLAGS := $(CFLAGS)
6+
7+
main:
8+
go generate
9+
go build -o parser .

kprobe.c

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// +build ignore
2+
3+
#include "bpf_tracing.h"
4+
#include "common.h"
5+
#include <linux/types.h>
6+
#define TASK_COMM_LEN 16
7+
8+
#define EVENT_TYPE_RECV 0
9+
#define EVENT_TYPE_SEND 1
10+
11+
char __license[] SEC("license") = "Dual MIT/GPL";
12+
13+
struct bpf_map_def SEC("maps/connectlist") connectlist = {
14+
.type = BPF_MAP_TYPE_HASH,
15+
.key_size = sizeof(u32),
16+
.value_size = sizeof(void *),
17+
.max_entries = 256,
18+
};
19+
20+
struct bpf_map_def SEC("maps/acceptlist") acceptlist = {
21+
.type = BPF_MAP_TYPE_HASH,
22+
.key_size = sizeof(u32),
23+
.value_size = sizeof(void *),
24+
.max_entries = 256,
25+
};
26+
27+
struct bpf_map_def SEC("maps/recvfromlist") recvfromlist = {
28+
.type = BPF_MAP_TYPE_HASH,
29+
.key_size = sizeof(u32),
30+
.value_size = sizeof(void *),
31+
.max_entries = 256,
32+
};
33+
34+
struct bpf_map_def SEC("maps/sendtolist") sendtolist = {
35+
.type = BPF_MAP_TYPE_HASH,
36+
.key_size = sizeof(u32),
37+
.value_size = sizeof(void *),
38+
.max_entries = 256,
39+
};
40+
41+
struct bpf_map_def SEC("maps/dataevent") dataevent = {
42+
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
43+
};
44+
45+
struct dataevent_t {
46+
u8 type;
47+
char buf[1024];
48+
};
49+
50+
struct bpf_map_def SEC("maps/messagelist") messagelist = {
51+
.type = BPF_MAP_TYPE_ARRAY,
52+
.key_size = sizeof(u32),
53+
.value_size = sizeof(struct dataevent_t),
54+
.max_entries = 1,
55+
};
56+
57+
58+
//
59+
// tcp_v4_connect
60+
//
61+
SEC("kprobe/tcp_v4_connect")
62+
int kprobe__tcp_v4_connect(struct pt_regs *ctx) {
63+
u32 pid = bpf_get_current_pid_tgid();
64+
65+
struct sock *sk;
66+
sk = (struct sock *)PT_REGS_PARM1(ctx);
67+
68+
char comm[TASK_COMM_LEN];
69+
bpf_get_current_comm(&comm, sizeof(comm));
70+
if (comm[0] == 'c' && comm[1] == 'u') {
71+
bpf_map_update_elem(&connectlist, &pid, &sk, BPF_ANY);
72+
}
73+
return 0;
74+
}
75+
SEC("kretprobe/tcp_v4_connect")
76+
int kretprobe__tcp_v4_connect(struct pt_regs *ctx) {
77+
u32 pid = bpf_get_current_pid_tgid();
78+
79+
struct sock *sk;
80+
sk = bpf_map_lookup_elem(&connectlist, &pid);
81+
if (sk == 0) {
82+
return 0;
83+
}
84+
// bpf_trace_printk("sockp->sk_family: %d\\n", sk->__sk_common.skc_dport);
85+
return 0;
86+
}
87+
88+
//
89+
// recvfrom
90+
//
91+
SEC("kprobe/sys_recvfrom")
92+
int kprobe__sys_recvfrom(struct pt_regs *ctx) {
93+
char *buf;
94+
buf = (char *)PT_REGS_PARM2(ctx);
95+
96+
u32 pid = bpf_get_current_pid_tgid();
97+
98+
struct sock *sk;
99+
sk = bpf_map_lookup_elem(&connectlist, &pid);
100+
if (sk == 0)
101+
return 0;
102+
bpf_map_update_elem(&recvfromlist, &pid, &buf, BPF_ANY);
103+
return 0;
104+
}
105+
SEC("kretprobe/sys_recvfrom")
106+
int kretprobe__sys_recvfrom(struct pt_regs *ctx) {
107+
u32 pid = bpf_get_current_pid_tgid();
108+
109+
char **buf, *bufp;
110+
buf = bpf_map_lookup_elem(&recvfromlist, &pid);
111+
if (buf == 0)
112+
return 0;
113+
bufp = *buf;
114+
115+
// Create Buffer on BPF map
116+
// BPF stack size is limited to 512 bytes
117+
int zero = 0;
118+
struct dataevent_t* data = bpf_map_lookup_elem(&messagelist, &zero);
119+
if (!data)
120+
return 0;
121+
bpf_probe_read(&data->buf, sizeof(data->buf), (void *)bufp);
122+
123+
data->type = EVENT_TYPE_RECV;
124+
bpf_perf_event_output(ctx, &dataevent, BPF_F_CURRENT_CPU, data, sizeof(*data));
125+
bpf_map_delete_elem(&recvfromlist, &pid);
126+
return 0;
127+
}
128+
129+
//
130+
// sendto
131+
//
132+
SEC("kprobe/sys_sendto")
133+
int kprobe__sys_sendto(struct pt_regs *ctx) {
134+
char *buf;
135+
buf = (char *)PT_REGS_PARM2(ctx);
136+
137+
u32 pid = bpf_get_current_pid_tgid();
138+
139+
struct sock *sk;
140+
sk = bpf_map_lookup_elem(&connectlist, &pid);
141+
if (sk == 0)
142+
return 0;
143+
bpf_map_update_elem(&sendtolist, &pid, &buf, BPF_ANY);
144+
return 0;
145+
}
146+
SEC("kretprobe/sys_sendto")
147+
int kretprobe__sys_sendto(struct pt_regs *ctx) {
148+
u32 pid = bpf_get_current_pid_tgid();
149+
150+
char **buf, *bufp;
151+
buf = bpf_map_lookup_elem(&sendtolist, &pid);
152+
if (buf == 0)
153+
return 0;
154+
bufp = *buf;
155+
156+
// Create Buffer on BPF map
157+
// BPF stack size is limited to 512 bytes
158+
int zero = 0;
159+
struct dataevent_t* data = bpf_map_lookup_elem(&messagelist, &zero);
160+
if (!data)
161+
return 0;
162+
data->type = EVENT_TYPE_SEND;
163+
bpf_probe_read(&data->buf, sizeof(data->buf), (void *)bufp);
164+
165+
bpf_perf_event_output(ctx, &dataevent, BPF_F_CURRENT_CPU, data, sizeof(*data));
166+
bpf_map_delete_elem(&sendtolist, &pid);
167+
return 0;
168+
}

main.go

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
//go:build linux
2+
// +build linux
3+
4+
package main
5+
6+
import (
7+
"bufio"
8+
"bytes"
9+
"encoding/binary"
10+
"errors"
11+
"fmt"
12+
"log"
13+
"net/http"
14+
"os"
15+
"os/signal"
16+
"strconv"
17+
"strings"
18+
"syscall"
19+
"time"
20+
21+
"github.com/cilium/ebpf/link"
22+
"github.com/cilium/ebpf/perf"
23+
"github.com/cilium/ebpf/rlimit"
24+
"github.com/fatih/color"
25+
"golang.org/x/sys/unix"
26+
)
27+
28+
import "C"
29+
30+
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -target native bpf kprobe.c -- -I../headers -I /usr/include -I /usr/include/x86_64-linux-gnu
31+
32+
type dataEvent struct {
33+
Type uint8
34+
Buf [1024]byte
35+
}
36+
37+
func main() {
38+
39+
// Allow the current process to lock memory for eBPF resources.
40+
if err := rlimit.RemoveMemlock(); err != nil {
41+
log.Fatal(err)
42+
}
43+
44+
45+
// Load pre-compiled programs and maps into the kernel.
46+
objs := bpfObjects{}
47+
if err := loadBpfObjects(&objs, nil); err != nil {
48+
log.Fatalf("loading objects: %v", err)
49+
}
50+
defer objs.Close()
51+
52+
//TcpV4Connect
53+
kprobeTcpV4Connect, err := link.Kprobe("tcp_v4_connect", objs.KprobeTcpV4Connect)
54+
if err != nil {
55+
log.Fatalf("opening kprobe: %s", err)
56+
}
57+
defer kprobeTcpV4Connect.Close()
58+
59+
kretprobeTcpV4Connect, err := link.Kretprobe("tcp_v4_connect", objs.KretprobeTcpV4Connect)
60+
if err != nil {
61+
log.Fatalf("opening kprobe: %s", err)
62+
}
63+
defer kretprobeTcpV4Connect.Close()
64+
65+
// SysRecvfrom
66+
kprobeSysRecvfrom, err := link.Kprobe("sys_recvfrom", objs.KprobeSysRecvfrom)
67+
if err != nil {
68+
log.Fatalf("opening kprobe: %s", err)
69+
}
70+
defer kprobeSysRecvfrom.Close()
71+
72+
kretprobeSysRecvfrom, err := link.Kretprobe("sys_recvfrom", objs.KretprobeSysRecvfrom)
73+
if err != nil {
74+
log.Fatalf("opening kprobe: %s", err)
75+
}
76+
defer kretprobeSysRecvfrom.Close()
77+
78+
// SysSendto
79+
kprobeSysSendto, err := link.Kprobe("sys_sendto", objs.KprobeSysSendto)
80+
if err != nil {
81+
log.Fatalf("opening kprobe: %s", err)
82+
}
83+
defer kprobeSysSendto.Close()
84+
85+
kretprobeSysSendto, err := link.Kretprobe("sys_sendto", objs.KretprobeSysSendto)
86+
if err != nil {
87+
log.Fatalf("opening kprobe: %s", err)
88+
}
89+
defer kretprobeSysSendto.Close()
90+
91+
92+
stopper := make(chan os.Signal, 1)
93+
signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)
94+
95+
rd, err := perf.NewReader(objs.Dataevent, os.Getpagesize())
96+
if err != nil {
97+
log.Fatalf("creating perf event reader: %s", err)
98+
}
99+
defer rd.Close()
100+
101+
go func() {
102+
// Wait for a signal and close the perf reader,
103+
// which will interrupt rd.Read() and make the program exit.
104+
<-stopper
105+
log.Println("Received signal, exiting program..")
106+
107+
if err := rd.Close(); err != nil {
108+
log.Fatalf("closing perf event reader: %s", err)
109+
}
110+
}()
111+
112+
log.Printf("Listening for events..")
113+
114+
request := ""
115+
response := ""
116+
var event dataEvent
117+
for {
118+
record, err := rd.Read()
119+
if err != nil {
120+
if errors.Is(err, perf.ErrClosed) {
121+
return
122+
}
123+
log.Printf("reading from perf event reader: %s", err)
124+
continue
125+
}
126+
127+
if record.LostSamples != 0 {
128+
log.Printf("perf event ring buffer full, dropped %d samples", record.LostSamples)
129+
continue
130+
}
131+
132+
// Parse the perf event entry into a bpfEvent structure.
133+
if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {
134+
log.Printf("parsing perf event: %s", err)
135+
continue
136+
}
137+
138+
//log.Printf("type: %d", event.Type)
139+
//log.Printf("Buf: %s", unix.ByteSliceToString(event.Buf[:]))
140+
141+
if event.Type == 1 {
142+
request += unix.ByteSliceToString(event.Buf[:])
143+
} else if event.Type == 0 {
144+
response += unix.ByteSliceToString(event.Buf[:])
145+
}
146+
req_rd := strings.NewReader(request)
147+
req_reader := bufio.NewReader(req_rd)
148+
req, err := http.ReadRequest(req_reader)
149+
if err != nil {
150+
//fmt.Println(err)
151+
continue
152+
}
153+
res_rd := strings.NewReader(response)
154+
res_reader := bufio.NewReader(res_rd)
155+
res, err := http.ReadResponse(res_reader, req)
156+
if err != nil {
157+
//fmt.Println(err)
158+
continue
159+
}
160+
code_color := color.New(color.FgWhite, color.BgBlack).SprintFunc()
161+
switch {
162+
case res.StatusCode >= 500:
163+
code_color = color.New(color.FgWhite, color.BgHiRed).SprintFunc()
164+
case res.StatusCode >= 400:
165+
code_color = color.New(color.FgWhite, color.BgHiBlue).SprintFunc()
166+
case res.StatusCode >= 300:
167+
code_color = color.New(color.FgBlack, color.BgHiWhite).SprintFunc()
168+
case res.StatusCode >= 200:
169+
code_color = color.New(color.FgWhite, color.BgHiGreen).SprintFunc()
170+
}
171+
172+
fmt.Printf("%s |%-s| %-15s | %-20s\n", time.Now().Format("2006/01/02 03:04:05"), code_color(" " + strconv.Itoa(res.StatusCode) + " "), req.Host, req.RequestURI)
173+
request=""
174+
response=""
175+
/*fmt.Println(req.Method)
176+
fmt.Println(req.Host)
177+
fmt.Println(req.RemoteAddr)
178+
fmt.Println(res.Status)
179+
fmt.Println(res.Close)*/
180+
}
181+
182+
}

0 commit comments

Comments
 (0)