1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
| // ./caller_tuple/main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Resp struct {
Errno int64 `json:"errno"`
Msg string `json:"msg"`
}
func Echo(c *gin.Context) {
req, _ := http.NewRequest(http.MethodGet, "http://baidu.com", nil)
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusOK, &Resp{Errno: 1, Msg: "request error"})
return
}
defer resp.Body.Close()
c.JSON(http.StatusOK, &Resp{Errno: 0, Msg: "ok"})
return
}
func main() {
r := gin.Default()
srv := &http.Server{
Addr: "0.0.0.0:3344",
}
r.GET("/echo", Echo)
srv.Handler = r
srv.ListenAndServe()
}
// caller_tuple/caller.bt
#!/usr/bin/env bpftrace
#define AF_INET 2
struct sock_common {
union {
struct {
__be32 skc_daddr;
__be32 skc_rcv_saddr;
};
};
union {
unsigned int skc_hash;
__u16 skc_u16hashes[2];
};
union {
struct {
__be16 skc_dport;
__u16 skc_num;
};
};
short unsigned int skc_family;
};
struct sock {
struct sock_common __sk_common;
};
BEGIN{
printf("start to gather caller info.
");
@caller[pid] = "none";
}
// 这里通过 uprobe 来便捷的获取会话信息。同时将信息写入bpf_map
uprobe:./caller_tuple:"net/http.serverHandler.ServeHTTP"{
$req_ptr = sarg3;
$method_ptr = *(uint64*)($req_ptr);
$method_len = *(uint64*)($req_ptr+8);
/* read request.url.Path */
$url_ptr = *(uint64*)($req_ptr + 16);
$path_ptr = *(uint64*)($url_ptr+56);
$path_len = *(uint64*)($url_ptr+64);
printf("get caller path: %s
", str($path_ptr, $path_len));
// 这里使用 pid 来作为 key 只是为了实现方便。实际可以采取其他更有区分性的内容。
@caller_ptr[pid]=$path_ptr;
@caller_len[pid]=$path_len;
}
// 通过 kprobe 来获取用户态无法获取的内容。同时通过 bpf_map 来控制生效及内容的交互。
kprobe:tcp_connect
{
if (@caller_ptr[pid] == 0){
return;
}
$ptr = @caller_ptr[pid];
$len = @caller_len[pid];
printf("caller info: %s
", str($ptr, $len));
@caller_ptr[pid] = 0;
@caller_len[pid] = 0;
$sk = ((struct sock *) arg0);
$inet_family = $sk->__sk_common.skc_family;
if ($inet_family == AF_INET) {
$daddr = ntop($sk->__sk_common.skc_daddr);
$saddr = ntop($sk->__sk_common.skc_rcv_saddr);
$lport = $sk->__sk_common.skc_num;
$dport = $sk->__sk_common.skc_dport;
$dport = (((($dport) >> 8) & 0xff) | ((($dport) & 0xff) << 8));
printf("%-8d %-16s ", pid, comm);
printf("%-39s %-6d %-39s %-6d
", $saddr, $lport, $daddr, $dport);
}
}
|