state.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #ifndef IPPROTO_TCP
  2. #define IPPROTO_TCP 6
  3. #endif
  4. #define MAX_CONNECTIONS 1000000
  5. struct tcp_event {
  6. __u64 fd;
  7. __u64 timestamp;
  8. __u64 duration;
  9. __u32 type;
  10. __u32 pid;
  11. __u64 bytes_sent;
  12. __u64 bytes_received;
  13. __u16 sport;
  14. __u16 dport;
  15. __u8 saddr[16];
  16. __u8 daddr[16];
  17. };
  18. struct {
  19. __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
  20. __uint(key_size, sizeof(int));
  21. __uint(value_size, sizeof(int));
  22. } tcp_listen_events SEC(".maps");
  23. struct {
  24. __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
  25. __uint(key_size, sizeof(int));
  26. __uint(value_size, sizeof(int));
  27. } tcp_connect_events SEC(".maps");
  28. struct trace_event_raw_inet_sock_set_state__stub {
  29. __u64 unused;
  30. void *skaddr;
  31. int oldstate;
  32. int newstate;
  33. __u16 sport;
  34. __u16 dport;
  35. __u16 family;
  36. #if __KERNEL_FROM >= 506
  37. __u16 protocol;
  38. #else
  39. __u8 protocol;
  40. #endif
  41. __u8 saddr[4];
  42. __u8 daddr[4];
  43. __u8 saddr_v6[16];
  44. __u8 daddr_v6[16];
  45. };
  46. struct {
  47. __uint(type, BPF_MAP_TYPE_HASH);
  48. __uint(key_size, sizeof(__u64));
  49. __uint(value_size, sizeof(__u64));
  50. __uint(max_entries, 10240);
  51. } fd_by_pid_tgid SEC(".maps");
  52. struct connection_id {
  53. __u64 fd;
  54. __u32 pid;
  55. };
  56. struct {
  57. __uint(type, BPF_MAP_TYPE_LRU_HASH);
  58. __uint(key_size, sizeof(void *));
  59. __uint(value_size, sizeof(struct connection_id));
  60. __uint(max_entries, MAX_CONNECTIONS);
  61. } connection_id_by_socket SEC(".maps");
  62. struct connection {
  63. __u64 timestamp;
  64. __u64 bytes_sent;
  65. __u64 bytes_received;
  66. };
  67. struct {
  68. __uint(type, BPF_MAP_TYPE_LRU_HASH);
  69. __uint(key_size, sizeof(struct connection_id));
  70. __uint(value_size, sizeof(struct connection));
  71. __uint(max_entries, MAX_CONNECTIONS);
  72. } active_connections SEC(".maps");
  73. SEC("tracepoint/sock/inet_sock_set_state")
  74. int inet_sock_set_state(void *ctx)
  75. {
  76. struct trace_event_raw_inet_sock_set_state__stub args = {};
  77. if (bpf_probe_read(&args, sizeof(args), ctx) < 0) {
  78. return 0;
  79. }
  80. if (args.protocol != IPPROTO_TCP) {
  81. return 0;
  82. }
  83. __u64 id = bpf_get_current_pid_tgid();
  84. __u32 pid = id >> 32;
  85. if (args.oldstate == BPF_TCP_CLOSE && args.newstate == BPF_TCP_SYN_SENT) {
  86. __u64 *fdp = bpf_map_lookup_elem(&fd_by_pid_tgid, &id);
  87. if (!fdp) {
  88. return 0;
  89. }
  90. struct connection_id cid = {};
  91. cid.pid = pid;
  92. cid.fd = *fdp;
  93. struct connection conn = {};
  94. conn.timestamp = bpf_ktime_get_ns();
  95. bpf_map_delete_elem(&fd_by_pid_tgid, &id);
  96. bpf_map_update_elem(&connection_id_by_socket, &args.skaddr, &cid, BPF_ANY);
  97. bpf_map_update_elem(&active_connections, &cid, &conn, BPF_ANY);
  98. return 0;
  99. }
  100. __u64 fd = 0;
  101. __u32 type = 0;
  102. __u64 timestamp = 0;
  103. __u64 duration = 0;
  104. void *map = &tcp_connect_events;
  105. struct tcp_event e = {};
  106. if (args.oldstate == BPF_TCP_SYN_SENT) {
  107. struct connection_id *cid = bpf_map_lookup_elem(&connection_id_by_socket, &args.skaddr);
  108. if (!cid) {
  109. return 0;
  110. }
  111. struct connection *conn = bpf_map_lookup_elem(&active_connections, cid);
  112. if (!conn) {
  113. return 0;
  114. }
  115. if (args.newstate == BPF_TCP_ESTABLISHED) {
  116. timestamp = conn->timestamp;
  117. type = EVENT_TYPE_CONNECTION_OPEN;
  118. } else if (args.newstate == BPF_TCP_CLOSE) {
  119. bpf_map_delete_elem(&active_connections, cid);
  120. type = EVENT_TYPE_CONNECTION_ERROR;
  121. }
  122. duration = bpf_ktime_get_ns() - conn->timestamp;
  123. pid = cid->pid;
  124. fd = cid->fd;
  125. }
  126. if (args.oldstate == BPF_TCP_ESTABLISHED && (args.newstate == BPF_TCP_FIN_WAIT1 || args.newstate == BPF_TCP_CLOSE_WAIT)) {
  127. bpf_map_delete_elem(&connection_id_by_socket, &args.skaddr);
  128. }
  129. if (args.oldstate == BPF_TCP_CLOSE && args.newstate == BPF_TCP_LISTEN) {
  130. type = EVENT_TYPE_LISTEN_OPEN;
  131. map = &tcp_listen_events;
  132. }
  133. if (args.oldstate == BPF_TCP_LISTEN && args.newstate == BPF_TCP_CLOSE) {
  134. type = EVENT_TYPE_LISTEN_CLOSE;
  135. map = &tcp_listen_events;
  136. }
  137. if (type == 0) {
  138. return 0;
  139. }
  140. e.type = type;
  141. e.duration = duration;
  142. e.timestamp = timestamp;
  143. e.pid = pid;
  144. e.sport = args.sport;
  145. e.dport = args.dport;
  146. e.fd = fd;
  147. __builtin_memcpy(&e.saddr, &args.saddr_v6, sizeof(e.saddr));
  148. __builtin_memcpy(&e.daddr, &args.daddr_v6, sizeof(e.saddr));
  149. bpf_perf_event_output(ctx, map, BPF_F_CURRENT_CPU, &e, sizeof(e));
  150. return 0;
  151. }
  152. struct trace_event_raw_args_with_fd__stub {
  153. __u64 unused;
  154. long int id;
  155. __u64 fd;
  156. };
  157. SEC("tracepoint/syscalls/sys_enter_connect")
  158. int sys_enter_connect(void *ctx) {
  159. struct trace_event_raw_args_with_fd__stub args = {};
  160. if (bpf_probe_read(&args, sizeof(args), ctx) < 0) {
  161. return 0;
  162. }
  163. __u64 id = bpf_get_current_pid_tgid();
  164. bpf_map_update_elem(&fd_by_pid_tgid, &id, &args.fd, BPF_ANY);
  165. return 0;
  166. }
  167. SEC("tracepoint/syscalls/sys_exit_connect")
  168. int sys_exit_connect(struct trace_event_raw_sys_exit__stub* ctx) {
  169. __u64 id = bpf_get_current_pid_tgid();
  170. __u64 *fdp = bpf_map_lookup_elem(&fd_by_pid_tgid, &id);
  171. if (!fdp) {
  172. return 0;
  173. }
  174. struct connection_id cid = {};
  175. cid.pid = id >> 32;
  176. cid.fd = *fdp;
  177. struct connection *conn = bpf_map_lookup_elem(&active_connections, &cid);
  178. if (!conn && ctx->ret == 0) { // non-TCP connection
  179. struct connection conn = {};
  180. conn.timestamp = bpf_ktime_get_ns();
  181. bpf_map_update_elem(&active_connections, &cid, &conn, BPF_ANY);
  182. }
  183. bpf_map_delete_elem(&fd_by_pid_tgid, &id);
  184. return 0;
  185. }
  186. SEC("tracepoint/syscalls/sys_enter_close")
  187. int sys_enter_close(void *ctx) {
  188. struct trace_event_raw_args_with_fd__stub args = {};
  189. if (bpf_probe_read(&args, sizeof(args), ctx) < 0) {
  190. return 0;
  191. }
  192. __u64 id = bpf_get_current_pid_tgid();
  193. struct connection_id cid = {};
  194. cid.pid = id >> 32;
  195. cid.fd = args.fd;
  196. struct connection *conn = bpf_map_lookup_elem(&active_connections, &cid);
  197. if (conn) {
  198. struct tcp_event e = {};
  199. e.type = EVENT_TYPE_CONNECTION_CLOSE;
  200. e.pid = cid.pid;
  201. e.fd = cid.fd;
  202. e.bytes_sent = conn->bytes_sent;
  203. e.bytes_received = conn->bytes_received;
  204. e.timestamp = conn->timestamp;
  205. bpf_perf_event_output(ctx, &tcp_connect_events, BPF_F_CURRENT_CPU, &e, sizeof(e));
  206. bpf_map_delete_elem(&active_connections, &cid);
  207. }
  208. return 0;
  209. }