1bd4aed0eSJiong Wang // SPDX-License-Identifier: GPL-2.0
2bd4aed0eSJiong Wang // Copyright (c) 2018 Facebook
3bd4aed0eSJiong Wang
46cd4dcc3SFlorent Revest #include "vmlinux.h"
5bd4aed0eSJiong Wang
63e689141SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
73e689141SToke Høiland-Jørgensen #include <bpf/bpf_endian.h>
8*6fdd671bSFlorent Revest #include <bpf/bpf_tracing.h>
9bd4aed0eSJiong Wang
106cd4dcc3SFlorent Revest #define AF_INET6 10
116cd4dcc3SFlorent Revest
1269d96519SStanislav Fomichev struct socket_cookie {
1369d96519SStanislav Fomichev __u64 cookie_key;
1469d96519SStanislav Fomichev __u32 cookie_value;
15bd4aed0eSJiong Wang };
16bd4aed0eSJiong Wang
17df0b7792SAndrii Nakryiko struct {
18bc7430ccSAndrii Nakryiko __uint(type, BPF_MAP_TYPE_SK_STORAGE);
19bc7430ccSAndrii Nakryiko __uint(map_flags, BPF_F_NO_PREALLOC);
20bc7430ccSAndrii Nakryiko __type(key, int);
21bc7430ccSAndrii Nakryiko __type(value, struct socket_cookie);
22bc7430ccSAndrii Nakryiko } socket_cookies SEC(".maps");
2369d96519SStanislav Fomichev
24*6fdd671bSFlorent Revest /*
25*6fdd671bSFlorent Revest * These three programs get executed in a row on connect() syscalls. The
26*6fdd671bSFlorent Revest * userspace side of the test creates a client socket, issues a connect() on it
27*6fdd671bSFlorent Revest * and then checks that the local storage associated with this socket has:
28*6fdd671bSFlorent Revest * cookie_value == local_port << 8 | 0xFF
29*6fdd671bSFlorent Revest * The different parts of this cookie_value are appended by those hooks if they
30*6fdd671bSFlorent Revest * all agree on the output of bpf_get_socket_cookie().
31*6fdd671bSFlorent Revest */
32bd4aed0eSJiong Wang SEC("cgroup/connect6")
set_cookie(struct bpf_sock_addr * ctx)33bd4aed0eSJiong Wang int set_cookie(struct bpf_sock_addr *ctx)
34bd4aed0eSJiong Wang {
3569d96519SStanislav Fomichev struct socket_cookie *p;
36bd4aed0eSJiong Wang
37bd4aed0eSJiong Wang if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6)
38bd4aed0eSJiong Wang return 1;
39bd4aed0eSJiong Wang
4069d96519SStanislav Fomichev p = bpf_sk_storage_get(&socket_cookies, ctx->sk, 0,
4169d96519SStanislav Fomichev BPF_SK_STORAGE_GET_F_CREATE);
4269d96519SStanislav Fomichev if (!p)
4369d96519SStanislav Fomichev return 1;
4469d96519SStanislav Fomichev
45*6fdd671bSFlorent Revest p->cookie_value = 0xF;
4669d96519SStanislav Fomichev p->cookie_key = bpf_get_socket_cookie(ctx);
47bd4aed0eSJiong Wang
48bd4aed0eSJiong Wang return 1;
49bd4aed0eSJiong Wang }
50bd4aed0eSJiong Wang
51bd4aed0eSJiong Wang SEC("sockops")
update_cookie_sockops(struct bpf_sock_ops * ctx)52*6fdd671bSFlorent Revest int update_cookie_sockops(struct bpf_sock_ops *ctx)
53bd4aed0eSJiong Wang {
546cd4dcc3SFlorent Revest struct bpf_sock *sk = ctx->sk;
5569d96519SStanislav Fomichev struct socket_cookie *p;
56bd4aed0eSJiong Wang
57bd4aed0eSJiong Wang if (ctx->family != AF_INET6)
58bd4aed0eSJiong Wang return 1;
59bd4aed0eSJiong Wang
60bd4aed0eSJiong Wang if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB)
61bd4aed0eSJiong Wang return 1;
62bd4aed0eSJiong Wang
636cd4dcc3SFlorent Revest if (!sk)
64bd4aed0eSJiong Wang return 1;
65bd4aed0eSJiong Wang
666cd4dcc3SFlorent Revest p = bpf_sk_storage_get(&socket_cookies, sk, 0, 0);
6769d96519SStanislav Fomichev if (!p)
6869d96519SStanislav Fomichev return 1;
6969d96519SStanislav Fomichev
7069d96519SStanislav Fomichev if (p->cookie_key != bpf_get_socket_cookie(ctx))
7169d96519SStanislav Fomichev return 1;
7269d96519SStanislav Fomichev
73*6fdd671bSFlorent Revest p->cookie_value |= (ctx->local_port << 8);
74bd4aed0eSJiong Wang
75bd4aed0eSJiong Wang return 1;
76bd4aed0eSJiong Wang }
77bd4aed0eSJiong Wang
78*6fdd671bSFlorent Revest SEC("fexit/inet_stream_connect")
BPF_PROG(update_cookie_tracing,struct socket * sock,struct sockaddr * uaddr,int addr_len,int flags)79*6fdd671bSFlorent Revest int BPF_PROG(update_cookie_tracing, struct socket *sock,
80*6fdd671bSFlorent Revest struct sockaddr *uaddr, int addr_len, int flags)
81*6fdd671bSFlorent Revest {
82*6fdd671bSFlorent Revest struct socket_cookie *p;
83*6fdd671bSFlorent Revest
84*6fdd671bSFlorent Revest if (uaddr->sa_family != AF_INET6)
85*6fdd671bSFlorent Revest return 0;
86*6fdd671bSFlorent Revest
87*6fdd671bSFlorent Revest p = bpf_sk_storage_get(&socket_cookies, sock->sk, 0, 0);
88*6fdd671bSFlorent Revest if (!p)
89*6fdd671bSFlorent Revest return 0;
90*6fdd671bSFlorent Revest
91*6fdd671bSFlorent Revest if (p->cookie_key != bpf_get_socket_cookie(sock->sk))
92*6fdd671bSFlorent Revest return 0;
93*6fdd671bSFlorent Revest
94*6fdd671bSFlorent Revest p->cookie_value |= 0xF0;
95*6fdd671bSFlorent Revest
96*6fdd671bSFlorent Revest return 0;
97*6fdd671bSFlorent Revest }
98*6fdd671bSFlorent Revest
99bd4aed0eSJiong Wang char _license[] SEC("license") = "GPL";
100