1991e35eeSJohn Fastabend /* SPDX-License-Identifier: GPL-2.0 */ 2991e35eeSJohn Fastabend /* Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io */ 3991e35eeSJohn Fastabend #include <stddef.h> 4991e35eeSJohn Fastabend #include <string.h> 5991e35eeSJohn Fastabend #include <linux/bpf.h> 6991e35eeSJohn Fastabend #include <linux/if_ether.h> 7991e35eeSJohn Fastabend #include <linux/if_packet.h> 8991e35eeSJohn Fastabend #include <linux/ip.h> 9991e35eeSJohn Fastabend #include <linux/ipv6.h> 10991e35eeSJohn Fastabend #include <linux/in.h> 11991e35eeSJohn Fastabend #include <linux/udp.h> 12991e35eeSJohn Fastabend #include <linux/tcp.h> 13991e35eeSJohn Fastabend #include <linux/pkt_cls.h> 14991e35eeSJohn Fastabend #include <sys/socket.h> 15991e35eeSJohn Fastabend #include <bpf/bpf_helpers.h> 16991e35eeSJohn Fastabend #include <bpf/bpf_endian.h> 17991e35eeSJohn Fastabend 18991e35eeSJohn Fastabend /* Sockmap sample program connects a client and a backend together 19991e35eeSJohn Fastabend * using cgroups. 20991e35eeSJohn Fastabend * 21991e35eeSJohn Fastabend * client:X <---> frontend:80 client:X <---> backend:80 22991e35eeSJohn Fastabend * 23991e35eeSJohn Fastabend * For simplicity we hard code values here and bind 1:1. The hard 24991e35eeSJohn Fastabend * coded values are part of the setup in sockmap.sh script that 25991e35eeSJohn Fastabend * is associated with this BPF program. 26991e35eeSJohn Fastabend * 27991e35eeSJohn Fastabend * The bpf_printk is verbose and prints information as connections 28991e35eeSJohn Fastabend * are established and verdicts are decided. 29991e35eeSJohn Fastabend */ 30991e35eeSJohn Fastabend 31991e35eeSJohn Fastabend struct { 32991e35eeSJohn Fastabend __uint(type, TEST_MAP_TYPE); 33991e35eeSJohn Fastabend __uint(max_entries, 20); 34991e35eeSJohn Fastabend __uint(key_size, sizeof(int)); 35991e35eeSJohn Fastabend __uint(value_size, sizeof(int)); 36991e35eeSJohn Fastabend } sock_map SEC(".maps"); 37991e35eeSJohn Fastabend 38991e35eeSJohn Fastabend struct { 39991e35eeSJohn Fastabend __uint(type, TEST_MAP_TYPE); 40991e35eeSJohn Fastabend __uint(max_entries, 20); 41991e35eeSJohn Fastabend __uint(key_size, sizeof(int)); 42991e35eeSJohn Fastabend __uint(value_size, sizeof(int)); 43991e35eeSJohn Fastabend } sock_map_txmsg SEC(".maps"); 44991e35eeSJohn Fastabend 45991e35eeSJohn Fastabend struct { 46991e35eeSJohn Fastabend __uint(type, TEST_MAP_TYPE); 47991e35eeSJohn Fastabend __uint(max_entries, 20); 48991e35eeSJohn Fastabend __uint(key_size, sizeof(int)); 49991e35eeSJohn Fastabend __uint(value_size, sizeof(int)); 50991e35eeSJohn Fastabend } sock_map_redir SEC(".maps"); 51991e35eeSJohn Fastabend 52991e35eeSJohn Fastabend struct { 53991e35eeSJohn Fastabend __uint(type, BPF_MAP_TYPE_ARRAY); 54991e35eeSJohn Fastabend __uint(max_entries, 1); 55991e35eeSJohn Fastabend __type(key, int); 56991e35eeSJohn Fastabend __type(value, int); 57991e35eeSJohn Fastabend } sock_apply_bytes SEC(".maps"); 58991e35eeSJohn Fastabend 59991e35eeSJohn Fastabend struct { 60991e35eeSJohn Fastabend __uint(type, BPF_MAP_TYPE_ARRAY); 61991e35eeSJohn Fastabend __uint(max_entries, 1); 62991e35eeSJohn Fastabend __type(key, int); 63991e35eeSJohn Fastabend __type(value, int); 64991e35eeSJohn Fastabend } sock_cork_bytes SEC(".maps"); 65991e35eeSJohn Fastabend 66991e35eeSJohn Fastabend struct { 67991e35eeSJohn Fastabend __uint(type, BPF_MAP_TYPE_ARRAY); 68991e35eeSJohn Fastabend __uint(max_entries, 6); 69991e35eeSJohn Fastabend __type(key, int); 70991e35eeSJohn Fastabend __type(value, int); 71991e35eeSJohn Fastabend } sock_bytes SEC(".maps"); 72991e35eeSJohn Fastabend 73991e35eeSJohn Fastabend struct { 74991e35eeSJohn Fastabend __uint(type, BPF_MAP_TYPE_ARRAY); 75991e35eeSJohn Fastabend __uint(max_entries, 1); 76991e35eeSJohn Fastabend __type(key, int); 77991e35eeSJohn Fastabend __type(value, int); 78991e35eeSJohn Fastabend } sock_redir_flags SEC(".maps"); 79991e35eeSJohn Fastabend 80991e35eeSJohn Fastabend struct { 81991e35eeSJohn Fastabend __uint(type, BPF_MAP_TYPE_ARRAY); 8253792fa4SJohn Fastabend __uint(max_entries, 3); 83991e35eeSJohn Fastabend __type(key, int); 84991e35eeSJohn Fastabend __type(value, int); 85991e35eeSJohn Fastabend } sock_skb_opts SEC(".maps"); 86991e35eeSJohn Fastabend 87463bac5fSJohn Fastabend struct { 88463bac5fSJohn Fastabend __uint(type, TEST_MAP_TYPE); 89463bac5fSJohn Fastabend __uint(max_entries, 20); 90463bac5fSJohn Fastabend __uint(key_size, sizeof(int)); 91463bac5fSJohn Fastabend __uint(value_size, sizeof(int)); 92463bac5fSJohn Fastabend } tls_sock_map SEC(".maps"); 93463bac5fSJohn Fastabend 94991e35eeSJohn Fastabend SEC("sk_skb1") 95991e35eeSJohn Fastabend int bpf_prog1(struct __sk_buff *skb) 96991e35eeSJohn Fastabend { 9753792fa4SJohn Fastabend int *f, two = 2; 9853792fa4SJohn Fastabend 9953792fa4SJohn Fastabend f = bpf_map_lookup_elem(&sock_skb_opts, &two); 10053792fa4SJohn Fastabend if (f && *f) { 10153792fa4SJohn Fastabend return *f; 10253792fa4SJohn Fastabend } 103991e35eeSJohn Fastabend return skb->len; 104991e35eeSJohn Fastabend } 105991e35eeSJohn Fastabend 106991e35eeSJohn Fastabend SEC("sk_skb2") 107991e35eeSJohn Fastabend int bpf_prog2(struct __sk_buff *skb) 108991e35eeSJohn Fastabend { 109991e35eeSJohn Fastabend __u32 lport = skb->local_port; 110991e35eeSJohn Fastabend __u32 rport = skb->remote_port; 111991e35eeSJohn Fastabend int len, *f, ret, zero = 0; 112991e35eeSJohn Fastabend __u64 flags = 0; 113991e35eeSJohn Fastabend 114991e35eeSJohn Fastabend if (lport == 10000) 115991e35eeSJohn Fastabend ret = 10; 116991e35eeSJohn Fastabend else 117991e35eeSJohn Fastabend ret = 1; 118991e35eeSJohn Fastabend 119991e35eeSJohn Fastabend len = (__u32)skb->data_end - (__u32)skb->data; 120991e35eeSJohn Fastabend f = bpf_map_lookup_elem(&sock_skb_opts, &zero); 121991e35eeSJohn Fastabend if (f && *f) { 122991e35eeSJohn Fastabend ret = 3; 123991e35eeSJohn Fastabend flags = *f; 124991e35eeSJohn Fastabend } 125991e35eeSJohn Fastabend 126991e35eeSJohn Fastabend #ifdef SOCKMAP 127991e35eeSJohn Fastabend return bpf_sk_redirect_map(skb, &sock_map, ret, flags); 128991e35eeSJohn Fastabend #else 129991e35eeSJohn Fastabend return bpf_sk_redirect_hash(skb, &sock_map, &ret, flags); 130991e35eeSJohn Fastabend #endif 131991e35eeSJohn Fastabend 132991e35eeSJohn Fastabend } 133991e35eeSJohn Fastabend 134463bac5fSJohn Fastabend SEC("sk_skb3") 135463bac5fSJohn Fastabend int bpf_prog3(struct __sk_buff *skb) 136463bac5fSJohn Fastabend { 137463bac5fSJohn Fastabend const int one = 1; 138463bac5fSJohn Fastabend int err, *f, ret = SK_PASS; 139463bac5fSJohn Fastabend void *data_end; 140463bac5fSJohn Fastabend char *c; 141463bac5fSJohn Fastabend 142463bac5fSJohn Fastabend err = bpf_skb_pull_data(skb, 19); 143463bac5fSJohn Fastabend if (err) 144463bac5fSJohn Fastabend goto tls_out; 145463bac5fSJohn Fastabend 146463bac5fSJohn Fastabend c = (char *)(long)skb->data; 147463bac5fSJohn Fastabend data_end = (void *)(long)skb->data_end; 148463bac5fSJohn Fastabend 149463bac5fSJohn Fastabend if (c + 18 < data_end) 150463bac5fSJohn Fastabend memcpy(&c[13], "PASS", 4); 151463bac5fSJohn Fastabend f = bpf_map_lookup_elem(&sock_skb_opts, &one); 152463bac5fSJohn Fastabend if (f && *f) { 153463bac5fSJohn Fastabend __u64 flags = 0; 154463bac5fSJohn Fastabend 155463bac5fSJohn Fastabend ret = 0; 156463bac5fSJohn Fastabend flags = *f; 157463bac5fSJohn Fastabend #ifdef SOCKMAP 158463bac5fSJohn Fastabend return bpf_sk_redirect_map(skb, &tls_sock_map, ret, flags); 159463bac5fSJohn Fastabend #else 160463bac5fSJohn Fastabend return bpf_sk_redirect_hash(skb, &tls_sock_map, &ret, flags); 161463bac5fSJohn Fastabend #endif 162463bac5fSJohn Fastabend } 163463bac5fSJohn Fastabend 164463bac5fSJohn Fastabend f = bpf_map_lookup_elem(&sock_skb_opts, &one); 165463bac5fSJohn Fastabend if (f && *f) 166463bac5fSJohn Fastabend ret = SK_DROP; 167463bac5fSJohn Fastabend tls_out: 168463bac5fSJohn Fastabend return ret; 169463bac5fSJohn Fastabend } 170463bac5fSJohn Fastabend 171991e35eeSJohn Fastabend SEC("sockops") 172991e35eeSJohn Fastabend int bpf_sockmap(struct bpf_sock_ops *skops) 173991e35eeSJohn Fastabend { 174991e35eeSJohn Fastabend __u32 lport, rport; 175991e35eeSJohn Fastabend int op, err = 0, index, key, ret; 176991e35eeSJohn Fastabend 177991e35eeSJohn Fastabend 178991e35eeSJohn Fastabend op = (int) skops->op; 179991e35eeSJohn Fastabend 180991e35eeSJohn Fastabend switch (op) { 181991e35eeSJohn Fastabend case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 182991e35eeSJohn Fastabend lport = skops->local_port; 183991e35eeSJohn Fastabend rport = skops->remote_port; 184991e35eeSJohn Fastabend 185991e35eeSJohn Fastabend if (lport == 10000) { 186991e35eeSJohn Fastabend ret = 1; 187991e35eeSJohn Fastabend #ifdef SOCKMAP 188991e35eeSJohn Fastabend err = bpf_sock_map_update(skops, &sock_map, &ret, 189991e35eeSJohn Fastabend BPF_NOEXIST); 190991e35eeSJohn Fastabend #else 191991e35eeSJohn Fastabend err = bpf_sock_hash_update(skops, &sock_map, &ret, 192991e35eeSJohn Fastabend BPF_NOEXIST); 193991e35eeSJohn Fastabend #endif 194991e35eeSJohn Fastabend } 195991e35eeSJohn Fastabend break; 196991e35eeSJohn Fastabend case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 197991e35eeSJohn Fastabend lport = skops->local_port; 198991e35eeSJohn Fastabend rport = skops->remote_port; 199991e35eeSJohn Fastabend 200991e35eeSJohn Fastabend if (bpf_ntohl(rport) == 10001) { 201991e35eeSJohn Fastabend ret = 10; 202991e35eeSJohn Fastabend #ifdef SOCKMAP 203991e35eeSJohn Fastabend err = bpf_sock_map_update(skops, &sock_map, &ret, 204991e35eeSJohn Fastabend BPF_NOEXIST); 205991e35eeSJohn Fastabend #else 206991e35eeSJohn Fastabend err = bpf_sock_hash_update(skops, &sock_map, &ret, 207991e35eeSJohn Fastabend BPF_NOEXIST); 208991e35eeSJohn Fastabend #endif 209991e35eeSJohn Fastabend } 210991e35eeSJohn Fastabend break; 211991e35eeSJohn Fastabend default: 212991e35eeSJohn Fastabend break; 213991e35eeSJohn Fastabend } 214991e35eeSJohn Fastabend 215991e35eeSJohn Fastabend return 0; 216991e35eeSJohn Fastabend } 217991e35eeSJohn Fastabend 218991e35eeSJohn Fastabend SEC("sk_msg1") 219991e35eeSJohn Fastabend int bpf_prog4(struct sk_msg_md *msg) 220991e35eeSJohn Fastabend { 221991e35eeSJohn Fastabend int *bytes, zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5; 222991e35eeSJohn Fastabend int *start, *end, *start_push, *end_push, *start_pop, *pop; 223991e35eeSJohn Fastabend 224991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); 225991e35eeSJohn Fastabend if (bytes) 226991e35eeSJohn Fastabend bpf_msg_apply_bytes(msg, *bytes); 227991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); 228991e35eeSJohn Fastabend if (bytes) 229991e35eeSJohn Fastabend bpf_msg_cork_bytes(msg, *bytes); 230991e35eeSJohn Fastabend start = bpf_map_lookup_elem(&sock_bytes, &zero); 231991e35eeSJohn Fastabend end = bpf_map_lookup_elem(&sock_bytes, &one); 232991e35eeSJohn Fastabend if (start && end) 233991e35eeSJohn Fastabend bpf_msg_pull_data(msg, *start, *end, 0); 234991e35eeSJohn Fastabend start_push = bpf_map_lookup_elem(&sock_bytes, &two); 235991e35eeSJohn Fastabend end_push = bpf_map_lookup_elem(&sock_bytes, &three); 236991e35eeSJohn Fastabend if (start_push && end_push) 237991e35eeSJohn Fastabend bpf_msg_push_data(msg, *start_push, *end_push, 0); 238991e35eeSJohn Fastabend start_pop = bpf_map_lookup_elem(&sock_bytes, &four); 239991e35eeSJohn Fastabend pop = bpf_map_lookup_elem(&sock_bytes, &five); 240991e35eeSJohn Fastabend if (start_pop && pop) 241991e35eeSJohn Fastabend bpf_msg_pop_data(msg, *start_pop, *pop, 0); 242991e35eeSJohn Fastabend return SK_PASS; 243991e35eeSJohn Fastabend } 244991e35eeSJohn Fastabend 245991e35eeSJohn Fastabend SEC("sk_msg2") 246991e35eeSJohn Fastabend int bpf_prog6(struct sk_msg_md *msg) 247991e35eeSJohn Fastabend { 248991e35eeSJohn Fastabend int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, key = 0; 249991e35eeSJohn Fastabend int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop, *f; 250991e35eeSJohn Fastabend __u64 flags = 0; 251991e35eeSJohn Fastabend 252991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); 253991e35eeSJohn Fastabend if (bytes) 254991e35eeSJohn Fastabend bpf_msg_apply_bytes(msg, *bytes); 255991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); 256991e35eeSJohn Fastabend if (bytes) 257991e35eeSJohn Fastabend bpf_msg_cork_bytes(msg, *bytes); 258991e35eeSJohn Fastabend 259991e35eeSJohn Fastabend start = bpf_map_lookup_elem(&sock_bytes, &zero); 260991e35eeSJohn Fastabend end = bpf_map_lookup_elem(&sock_bytes, &one); 261991e35eeSJohn Fastabend if (start && end) 262991e35eeSJohn Fastabend bpf_msg_pull_data(msg, *start, *end, 0); 263991e35eeSJohn Fastabend 264991e35eeSJohn Fastabend start_push = bpf_map_lookup_elem(&sock_bytes, &two); 265991e35eeSJohn Fastabend end_push = bpf_map_lookup_elem(&sock_bytes, &three); 266991e35eeSJohn Fastabend if (start_push && end_push) 267991e35eeSJohn Fastabend bpf_msg_push_data(msg, *start_push, *end_push, 0); 268991e35eeSJohn Fastabend 269991e35eeSJohn Fastabend start_pop = bpf_map_lookup_elem(&sock_bytes, &four); 270991e35eeSJohn Fastabend pop = bpf_map_lookup_elem(&sock_bytes, &five); 271991e35eeSJohn Fastabend if (start_pop && pop) 272991e35eeSJohn Fastabend bpf_msg_pop_data(msg, *start_pop, *pop, 0); 273991e35eeSJohn Fastabend 274991e35eeSJohn Fastabend f = bpf_map_lookup_elem(&sock_redir_flags, &zero); 275991e35eeSJohn Fastabend if (f && *f) { 276991e35eeSJohn Fastabend key = 2; 277991e35eeSJohn Fastabend flags = *f; 278991e35eeSJohn Fastabend } 279991e35eeSJohn Fastabend #ifdef SOCKMAP 280991e35eeSJohn Fastabend return bpf_msg_redirect_map(msg, &sock_map_redir, key, flags); 281991e35eeSJohn Fastabend #else 282991e35eeSJohn Fastabend return bpf_msg_redirect_hash(msg, &sock_map_redir, &key, flags); 283991e35eeSJohn Fastabend #endif 284991e35eeSJohn Fastabend } 285991e35eeSJohn Fastabend 286d79a3212SJohn Fastabend SEC("sk_msg3") 287991e35eeSJohn Fastabend int bpf_prog8(struct sk_msg_md *msg) 288991e35eeSJohn Fastabend { 289991e35eeSJohn Fastabend void *data_end = (void *)(long) msg->data_end; 290991e35eeSJohn Fastabend void *data = (void *)(long) msg->data; 291991e35eeSJohn Fastabend int ret = 0, *bytes, zero = 0; 292991e35eeSJohn Fastabend 293991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); 294991e35eeSJohn Fastabend if (bytes) { 295991e35eeSJohn Fastabend ret = bpf_msg_apply_bytes(msg, *bytes); 296991e35eeSJohn Fastabend if (ret) 297991e35eeSJohn Fastabend return SK_DROP; 298991e35eeSJohn Fastabend } else { 299991e35eeSJohn Fastabend return SK_DROP; 300991e35eeSJohn Fastabend } 301991e35eeSJohn Fastabend return SK_PASS; 302991e35eeSJohn Fastabend } 303d79a3212SJohn Fastabend SEC("sk_msg4") 304991e35eeSJohn Fastabend int bpf_prog9(struct sk_msg_md *msg) 305991e35eeSJohn Fastabend { 306991e35eeSJohn Fastabend void *data_end = (void *)(long) msg->data_end; 307991e35eeSJohn Fastabend void *data = (void *)(long) msg->data; 308991e35eeSJohn Fastabend int ret = 0, *bytes, zero = 0; 309991e35eeSJohn Fastabend 310991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); 311991e35eeSJohn Fastabend if (bytes) { 312991e35eeSJohn Fastabend if (((__u64)data_end - (__u64)data) >= *bytes) 313991e35eeSJohn Fastabend return SK_PASS; 314991e35eeSJohn Fastabend ret = bpf_msg_cork_bytes(msg, *bytes); 315991e35eeSJohn Fastabend if (ret) 316991e35eeSJohn Fastabend return SK_DROP; 317991e35eeSJohn Fastabend } 318991e35eeSJohn Fastabend return SK_PASS; 319991e35eeSJohn Fastabend } 320991e35eeSJohn Fastabend 321d79a3212SJohn Fastabend SEC("sk_msg5") 322991e35eeSJohn Fastabend int bpf_prog10(struct sk_msg_md *msg) 323991e35eeSJohn Fastabend { 324991e35eeSJohn Fastabend int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop; 325991e35eeSJohn Fastabend int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5; 326991e35eeSJohn Fastabend 327991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); 328991e35eeSJohn Fastabend if (bytes) 329991e35eeSJohn Fastabend bpf_msg_apply_bytes(msg, *bytes); 330991e35eeSJohn Fastabend bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); 331991e35eeSJohn Fastabend if (bytes) 332991e35eeSJohn Fastabend bpf_msg_cork_bytes(msg, *bytes); 333991e35eeSJohn Fastabend start = bpf_map_lookup_elem(&sock_bytes, &zero); 334991e35eeSJohn Fastabend end = bpf_map_lookup_elem(&sock_bytes, &one); 335991e35eeSJohn Fastabend if (start && end) 336991e35eeSJohn Fastabend bpf_msg_pull_data(msg, *start, *end, 0); 337991e35eeSJohn Fastabend start_push = bpf_map_lookup_elem(&sock_bytes, &two); 338991e35eeSJohn Fastabend end_push = bpf_map_lookup_elem(&sock_bytes, &three); 339991e35eeSJohn Fastabend if (start_push && end_push) 340991e35eeSJohn Fastabend bpf_msg_push_data(msg, *start_push, *end_push, 0); 341991e35eeSJohn Fastabend start_pop = bpf_map_lookup_elem(&sock_bytes, &four); 342991e35eeSJohn Fastabend pop = bpf_map_lookup_elem(&sock_bytes, &five); 343991e35eeSJohn Fastabend if (start_pop && pop) 344991e35eeSJohn Fastabend bpf_msg_pop_data(msg, *start_pop, *pop, 0); 345991e35eeSJohn Fastabend return SK_DROP; 346991e35eeSJohn Fastabend } 347991e35eeSJohn Fastabend 348991e35eeSJohn Fastabend int _version SEC("version") = 1; 349991e35eeSJohn Fastabend char _license[] SEC("license") = "GPL"; 350