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