1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2018 Facebook |
3 | |
4 | #include "vmlinux.h" |
5 | |
6 | #include <bpf/bpf_helpers.h> |
7 | #include <bpf/bpf_endian.h> |
8 | #include <bpf/bpf_tracing.h> |
9 | |
10 | #define AF_INET6 10 |
11 | |
12 | struct socket_cookie { |
13 | __u64 cookie_key; |
14 | __u32 cookie_value; |
15 | }; |
16 | |
17 | struct { |
18 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
19 | __uint(map_flags, BPF_F_NO_PREALLOC); |
20 | __type(key, int); |
21 | __type(value, struct socket_cookie); |
22 | } socket_cookies SEC(".maps" ); |
23 | |
24 | /* |
25 | * These three programs get executed in a row on connect() syscalls. The |
26 | * userspace side of the test creates a client socket, issues a connect() on it |
27 | * and then checks that the local storage associated with this socket has: |
28 | * cookie_value == local_port << 8 | 0xFF |
29 | * The different parts of this cookie_value are appended by those hooks if they |
30 | * all agree on the output of bpf_get_socket_cookie(). |
31 | */ |
32 | SEC("cgroup/connect6" ) |
33 | int set_cookie(struct bpf_sock_addr *ctx) |
34 | { |
35 | struct socket_cookie *p; |
36 | |
37 | if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) |
38 | return 1; |
39 | |
40 | p = bpf_sk_storage_get(&socket_cookies, ctx->sk, 0, |
41 | BPF_SK_STORAGE_GET_F_CREATE); |
42 | if (!p) |
43 | return 1; |
44 | |
45 | p->cookie_value = 0xF; |
46 | p->cookie_key = bpf_get_socket_cookie(ctx); |
47 | |
48 | return 1; |
49 | } |
50 | |
51 | SEC("sockops" ) |
52 | int update_cookie_sockops(struct bpf_sock_ops *ctx) |
53 | { |
54 | struct bpf_sock *sk = ctx->sk; |
55 | struct socket_cookie *p; |
56 | |
57 | if (ctx->family != AF_INET6) |
58 | return 1; |
59 | |
60 | if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB) |
61 | return 1; |
62 | |
63 | if (!sk) |
64 | return 1; |
65 | |
66 | p = bpf_sk_storage_get(&socket_cookies, sk, 0, 0); |
67 | if (!p) |
68 | return 1; |
69 | |
70 | if (p->cookie_key != bpf_get_socket_cookie(ctx)) |
71 | return 1; |
72 | |
73 | p->cookie_value |= (ctx->local_port << 8); |
74 | |
75 | return 1; |
76 | } |
77 | |
78 | SEC("fexit/inet_stream_connect" ) |
79 | int BPF_PROG(update_cookie_tracing, struct socket *sock, |
80 | struct sockaddr *uaddr, int addr_len, int flags) |
81 | { |
82 | struct socket_cookie *p; |
83 | |
84 | if (uaddr->sa_family != AF_INET6) |
85 | return 0; |
86 | |
87 | p = bpf_sk_storage_get(&socket_cookies, sock->sk, 0, 0); |
88 | if (!p) |
89 | return 0; |
90 | |
91 | if (p->cookie_key != bpf_get_socket_cookie(sock->sk)) |
92 | return 0; |
93 | |
94 | p->cookie_value |= 0xF0; |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | char _license[] SEC("license" ) = "GPL" ; |
100 | |