xref: /linux/tools/testing/selftests/bpf/progs/cgroup_tcp_skb.c (revision 981368e1440b76f68b1ac8f5fb14e739f80ecc4e)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3 #include <linux/bpf.h>
4 #include <bpf/bpf_endian.h>
5 #include <bpf/bpf_helpers.h>
6 
7 #include <linux/if_ether.h>
8 #include <linux/in.h>
9 #include <linux/in6.h>
10 #include <linux/ipv6.h>
11 #include <linux/tcp.h>
12 
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 
16 #include "cgroup_tcp_skb.h"
17 
18 char _license[] SEC("license") = "GPL";
19 
20 __u16 g_sock_port = 0;
21 __u32 g_sock_state = 0;
22 int g_unexpected = 0;
23 __u32 g_packet_count = 0;
24 
25 int needed_tcp_pkt(struct __sk_buff *skb, struct tcphdr *tcph)
26 {
27 	struct ipv6hdr ip6h;
28 
29 	if (skb->protocol != bpf_htons(ETH_P_IPV6))
30 		return 0;
31 	if (bpf_skb_load_bytes(skb, 0, &ip6h, sizeof(ip6h)))
32 		return 0;
33 
34 	if (ip6h.nexthdr != IPPROTO_TCP)
35 		return 0;
36 
37 	if (bpf_skb_load_bytes(skb, sizeof(ip6h), tcph, sizeof(*tcph)))
38 		return 0;
39 
40 	if (tcph->source != bpf_htons(g_sock_port) &&
41 	    tcph->dest != bpf_htons(g_sock_port))
42 		return 0;
43 
44 	return 1;
45 }
46 
47 /* Run accept() on a socket in the cgroup to receive a new connection. */
48 static int egress_accept(struct tcphdr *tcph)
49 {
50 	if (g_sock_state ==  SYN_RECV_SENDING_SYN_ACK) {
51 		if (tcph->fin || !tcph->syn || !tcph->ack)
52 			g_unexpected++;
53 		else
54 			g_sock_state = SYN_RECV;
55 		return 1;
56 	}
57 
58 	return 0;
59 }
60 
61 static int ingress_accept(struct tcphdr *tcph)
62 {
63 	switch (g_sock_state) {
64 	case INIT:
65 		if (!tcph->syn || tcph->fin || tcph->ack)
66 			g_unexpected++;
67 		else
68 			g_sock_state = SYN_RECV_SENDING_SYN_ACK;
69 		break;
70 	case SYN_RECV:
71 		if (tcph->fin || tcph->syn || !tcph->ack)
72 			g_unexpected++;
73 		else
74 			g_sock_state = ESTABLISHED;
75 		break;
76 	default:
77 		return 0;
78 	}
79 
80 	return 1;
81 }
82 
83 /* Run connect() on a socket in the cgroup to start a new connection. */
84 static int egress_connect(struct tcphdr *tcph)
85 {
86 	if (g_sock_state == INIT) {
87 		if (!tcph->syn || tcph->fin || tcph->ack)
88 			g_unexpected++;
89 		else
90 			g_sock_state = SYN_SENT;
91 		return 1;
92 	}
93 
94 	return 0;
95 }
96 
97 static int ingress_connect(struct tcphdr *tcph)
98 {
99 	if (g_sock_state == SYN_SENT) {
100 		if (tcph->fin || !tcph->syn || !tcph->ack)
101 			g_unexpected++;
102 		else
103 			g_sock_state = ESTABLISHED;
104 		return 1;
105 	}
106 
107 	return 0;
108 }
109 
110 /* The connection is closed by the peer outside the cgroup. */
111 static int egress_close_remote(struct tcphdr *tcph)
112 {
113 	switch (g_sock_state) {
114 	case ESTABLISHED:
115 		break;
116 	case CLOSE_WAIT_SENDING_ACK:
117 		if (tcph->fin || tcph->syn || !tcph->ack)
118 			g_unexpected++;
119 		else
120 			g_sock_state = CLOSE_WAIT;
121 		break;
122 	case CLOSE_WAIT:
123 		if (!tcph->fin)
124 			g_unexpected++;
125 		else
126 			g_sock_state = LAST_ACK;
127 		break;
128 	default:
129 		return 0;
130 	}
131 
132 	return 1;
133 }
134 
135 static int ingress_close_remote(struct tcphdr *tcph)
136 {
137 	switch (g_sock_state) {
138 	case ESTABLISHED:
139 		if (tcph->fin)
140 			g_sock_state = CLOSE_WAIT_SENDING_ACK;
141 		break;
142 	case LAST_ACK:
143 		if (tcph->fin || tcph->syn || !tcph->ack)
144 			g_unexpected++;
145 		else
146 			g_sock_state = CLOSED;
147 		break;
148 	default:
149 		return 0;
150 	}
151 
152 	return 1;
153 }
154 
155 /* The connection is closed by the endpoint inside the cgroup. */
156 static int egress_close_local(struct tcphdr *tcph)
157 {
158 	switch (g_sock_state) {
159 	case ESTABLISHED:
160 		if (tcph->fin)
161 			g_sock_state = FIN_WAIT1;
162 		break;
163 	case TIME_WAIT_SENDING_ACK:
164 		if (tcph->fin || tcph->syn || !tcph->ack)
165 			g_unexpected++;
166 		else
167 			g_sock_state = TIME_WAIT;
168 		break;
169 	default:
170 		return 0;
171 	}
172 
173 	return 1;
174 }
175 
176 static int ingress_close_local(struct tcphdr *tcph)
177 {
178 	switch (g_sock_state) {
179 	case ESTABLISHED:
180 		break;
181 	case FIN_WAIT1:
182 		if (tcph->fin || tcph->syn || !tcph->ack)
183 			g_unexpected++;
184 		else
185 			g_sock_state = FIN_WAIT2;
186 		break;
187 	case FIN_WAIT2:
188 		if (!tcph->fin || tcph->syn || !tcph->ack)
189 			g_unexpected++;
190 		else
191 			g_sock_state = TIME_WAIT_SENDING_ACK;
192 		break;
193 	default:
194 		return 0;
195 	}
196 
197 	return 1;
198 }
199 
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.
202  *
203  * The connection is closed by the client side.
204  */
205 SEC("cgroup_skb/egress")
206 int server_egress(struct __sk_buff *skb)
207 {
208 	struct tcphdr tcph;
209 
210 	if (!needed_tcp_pkt(skb, &tcph))
211 		return 1;
212 
213 	g_packet_count++;
214 
215 	/* Egress of the server socket. */
216 	if (egress_accept(&tcph) || egress_close_remote(&tcph))
217 		return 1;
218 
219 	g_unexpected++;
220 	return 1;
221 }
222 
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.
225  *
226  * The connection is closed by the client side.
227  */
228 SEC("cgroup_skb/ingress")
229 int server_ingress(struct __sk_buff *skb)
230 {
231 	struct tcphdr tcph;
232 
233 	if (!needed_tcp_pkt(skb, &tcph))
234 		return 1;
235 
236 	g_packet_count++;
237 
238 	/* Ingress of the server socket. */
239 	if (ingress_accept(&tcph) || ingress_close_remote(&tcph))
240 		return 1;
241 
242 	g_unexpected++;
243 	return 1;
244 }
245 
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.
248  *
249  * The connection is closed by the server side.
250  */
251 SEC("cgroup_skb/egress")
252 int server_egress_srv(struct __sk_buff *skb)
253 {
254 	struct tcphdr tcph;
255 
256 	if (!needed_tcp_pkt(skb, &tcph))
257 		return 1;
258 
259 	g_packet_count++;
260 
261 	/* Egress of the server socket. */
262 	if (egress_accept(&tcph) || egress_close_local(&tcph))
263 		return 1;
264 
265 	g_unexpected++;
266 	return 1;
267 }
268 
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.
271  *
272  * The connection is closed by the server side.
273  */
274 SEC("cgroup_skb/ingress")
275 int server_ingress_srv(struct __sk_buff *skb)
276 {
277 	struct tcphdr tcph;
278 
279 	if (!needed_tcp_pkt(skb, &tcph))
280 		return 1;
281 
282 	g_packet_count++;
283 
284 	/* Ingress of the server socket. */
285 	if (ingress_accept(&tcph) || ingress_close_local(&tcph))
286 		return 1;
287 
288 	g_unexpected++;
289 	return 1;
290 }
291 
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.
294  *
295  * The connection is closed by the server side.
296  */
297 SEC("cgroup_skb/egress")
298 int client_egress_srv(struct __sk_buff *skb)
299 {
300 	struct tcphdr tcph;
301 
302 	if (!needed_tcp_pkt(skb, &tcph))
303 		return 1;
304 
305 	g_packet_count++;
306 
307 	/* Egress of the server socket. */
308 	if (egress_connect(&tcph) || egress_close_remote(&tcph))
309 		return 1;
310 
311 	g_unexpected++;
312 	return 1;
313 }
314 
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.
317  *
318  * The connection is closed by the server side.
319  */
320 SEC("cgroup_skb/ingress")
321 int client_ingress_srv(struct __sk_buff *skb)
322 {
323 	struct tcphdr tcph;
324 
325 	if (!needed_tcp_pkt(skb, &tcph))
326 		return 1;
327 
328 	g_packet_count++;
329 
330 	/* Ingress of the server socket. */
331 	if (ingress_connect(&tcph) || ingress_close_remote(&tcph))
332 		return 1;
333 
334 	g_unexpected++;
335 	return 1;
336 }
337 
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.
340  *
341  * The connection is closed by the client side.
342  */
343 SEC("cgroup_skb/egress")
344 int client_egress(struct __sk_buff *skb)
345 {
346 	struct tcphdr tcph;
347 
348 	if (!needed_tcp_pkt(skb, &tcph))
349 		return 1;
350 
351 	g_packet_count++;
352 
353 	/* Egress of the server socket. */
354 	if (egress_connect(&tcph) || egress_close_local(&tcph))
355 		return 1;
356 
357 	g_unexpected++;
358 	return 1;
359 }
360 
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.
363  *
364  * The connection is closed by the client side.
365  */
366 SEC("cgroup_skb/ingress")
367 int client_ingress(struct __sk_buff *skb)
368 {
369 	struct tcphdr tcph;
370 
371 	if (!needed_tcp_pkt(skb, &tcph))
372 		return 1;
373 
374 	g_packet_count++;
375 
376 	/* Ingress of the server socket. */
377 	if (ingress_connect(&tcph) || ingress_close_local(&tcph))
378 		return 1;
379 
380 	g_unexpected++;
381 	return 1;
382 }
383