~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/cgroup_tcp_skb.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php