1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
4 #include <bpf/bpf_endian.h>
5 #include <bpf/bpf_helpers.h>
7 #include <linux/if_ether.h>
10 #include <linux/ipv6.h>
11 #include <linux/tcp.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
16 #include "cgroup_tcp_skb.h"
18 char _license[] SEC("license") = "GPL";
20 __u16 g_sock_port = 0;
21 __u32 g_sock_state = 0;
23 __u32 g_packet_count = 0;
25 int needed_tcp_pkt(struct __sk_buff *skb, struct tcphdr *tcph)
29 if (skb->protocol != bpf_htons(ETH_P_IPV6))
31 if (bpf_skb_load_bytes(skb, 0, &ip6h, sizeof(ip6h)))
34 if (ip6h.nexthdr != IPPROTO_TCP)
37 if (bpf_skb_load_bytes(skb, sizeof(ip6h), tcph, sizeof(*tcph)))
40 if (tcph->source != bpf_htons(g_sock_port) &&
41 tcph->dest != bpf_htons(g_sock_port))
47 /* Run accept() on a socket in the cgroup to receive a new connection. */
48 static int egress_accept(struct tcphdr *tcph)
50 if (g_sock_state == SYN_RECV_SENDING_SYN_ACK) {
51 if (tcph->fin || !tcph->syn || !tcph->ack)
54 g_sock_state = SYN_RECV;
61 static int ingress_accept(struct tcphdr *tcph)
63 switch (g_sock_state) {
65 if (!tcph->syn || tcph->fin || tcph->ack)
68 g_sock_state = SYN_RECV_SENDING_SYN_ACK;
71 if (tcph->fin || tcph->syn || !tcph->ack)
74 g_sock_state = ESTABLISHED;
83 /* Run connect() on a socket in the cgroup to start a new connection. */
84 static int egress_connect(struct tcphdr *tcph)
86 if (g_sock_state == INIT) {
87 if (!tcph->syn || tcph->fin || tcph->ack)
90 g_sock_state = SYN_SENT;
97 static int ingress_connect(struct tcphdr *tcph)
99 if (g_sock_state == SYN_SENT) {
100 if (tcph->fin || !tcph->syn || !tcph->ack)
103 g_sock_state = ESTABLISHED;
110 /* The connection is closed by the peer outside the cgroup. */
111 static int egress_close_remote(struct tcphdr *tcph)
113 switch (g_sock_state) {
116 case CLOSE_WAIT_SENDING_ACK:
117 if (tcph->fin || tcph->syn || !tcph->ack)
120 g_sock_state = CLOSE_WAIT;
126 g_sock_state = LAST_ACK;
135 static int ingress_close_remote(struct tcphdr *tcph)
137 switch (g_sock_state) {
140 g_sock_state = CLOSE_WAIT_SENDING_ACK;
143 if (tcph->fin || tcph->syn || !tcph->ack)
146 g_sock_state = CLOSED;
155 /* The connection is closed by the endpoint inside the cgroup. */
156 static int egress_close_local(struct tcphdr *tcph)
158 switch (g_sock_state) {
161 g_sock_state = FIN_WAIT1;
163 case TIME_WAIT_SENDING_ACK:
164 if (tcph->fin || tcph->syn || !tcph->ack)
167 g_sock_state = TIME_WAIT;
176 static int ingress_close_local(struct tcphdr *tcph)
178 switch (g_sock_state) {
182 if (tcph->fin || tcph->syn || !tcph->ack)
185 g_sock_state = FIN_WAIT2;
188 if (!tcph->fin || tcph->syn || !tcph->ack)
191 g_sock_state = TIME_WAIT_SENDING_ACK;
200 /* Check the types of outgoing packets of a server socket to make sure they
201 * are consistent with the state of the server socket.
203 * The connection is closed by the client side.
205 SEC("cgroup_skb/egress")
206 int server_egress(struct __sk_buff *skb)
210 if (!needed_tcp_pkt(skb, &tcph))
215 /* Egress of the server socket. */
216 if (egress_accept(&tcph) || egress_close_remote(&tcph))
223 /* Check the types of incoming packets of a server socket to make sure they
224 * are consistent with the state of the server socket.
226 * The connection is closed by the client side.
228 SEC("cgroup_skb/ingress")
229 int server_ingress(struct __sk_buff *skb)
233 if (!needed_tcp_pkt(skb, &tcph))
238 /* Ingress of the server socket. */
239 if (ingress_accept(&tcph) || ingress_close_remote(&tcph))
246 /* Check the types of outgoing packets of a server socket to make sure they
247 * are consistent with the state of the server socket.
249 * The connection is closed by the server side.
251 SEC("cgroup_skb/egress")
252 int server_egress_srv(struct __sk_buff *skb)
256 if (!needed_tcp_pkt(skb, &tcph))
261 /* Egress of the server socket. */
262 if (egress_accept(&tcph) || egress_close_local(&tcph))
269 /* Check the types of incoming packets of a server socket to make sure they
270 * are consistent with the state of the server socket.
272 * The connection is closed by the server side.
274 SEC("cgroup_skb/ingress")
275 int server_ingress_srv(struct __sk_buff *skb)
279 if (!needed_tcp_pkt(skb, &tcph))
284 /* Ingress of the server socket. */
285 if (ingress_accept(&tcph) || ingress_close_local(&tcph))
292 /* Check the types of outgoing packets of a client socket to make sure they
293 * are consistent with the state of the client socket.
295 * The connection is closed by the server side.
297 SEC("cgroup_skb/egress")
298 int client_egress_srv(struct __sk_buff *skb)
302 if (!needed_tcp_pkt(skb, &tcph))
307 /* Egress of the server socket. */
308 if (egress_connect(&tcph) || egress_close_remote(&tcph))
315 /* Check the types of incoming packets of a client socket to make sure they
316 * are consistent with the state of the client socket.
318 * The connection is closed by the server side.
320 SEC("cgroup_skb/ingress")
321 int client_ingress_srv(struct __sk_buff *skb)
325 if (!needed_tcp_pkt(skb, &tcph))
330 /* Ingress of the server socket. */
331 if (ingress_connect(&tcph) || ingress_close_remote(&tcph))
338 /* Check the types of outgoing packets of a client socket to make sure they
339 * are consistent with the state of the client socket.
341 * The connection is closed by the client side.
343 SEC("cgroup_skb/egress")
344 int client_egress(struct __sk_buff *skb)
348 if (!needed_tcp_pkt(skb, &tcph))
353 /* Egress of the server socket. */
354 if (egress_connect(&tcph) || egress_close_local(&tcph))
361 /* Check the types of incoming packets of a client socket to make sure they
362 * are consistent with the state of the client socket.
364 * The connection is closed by the client side.
366 SEC("cgroup_skb/ingress")
367 int client_ingress(struct __sk_buff *skb)
371 if (!needed_tcp_pkt(skb, &tcph))
376 /* Ingress of the server socket. */
377 if (ingress_connect(&tcph) || ingress_close_local(&tcph))