1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3
4 #define _GNU_SOURCE
5 #include <sched.h>
6 #include <linux/socket.h>
7 #include <linux/tls.h>
8 #include <net/if.h>
9
10 #include "test_progs.h"
11 #include "cgroup_helpers.h"
12 #include "network_helpers.h"
13
14 #include "setget_sockopt.skel.h"
15
16 #define CG_NAME "/setget-sockopt-test"
17
18 static const char addr4_str[] = "127.0.0.1";
19 static const char addr6_str[] = "::1";
20 static struct setget_sockopt *skel;
21 static int cg_fd;
22
create_netns(void)23 static int create_netns(void)
24 {
25 if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
26 return -1;
27
28 if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up"))
29 return -1;
30
31 if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"),
32 "add veth"))
33 return -1;
34
35 if (!ASSERT_OK(system("ip link set dev binddevtest1 up"),
36 "bring veth up"))
37 return -1;
38
39 return 0;
40 }
41
test_tcp(int family)42 static void test_tcp(int family)
43 {
44 struct setget_sockopt__bss *bss = skel->bss;
45 int sfd, cfd;
46
47 memset(bss, 0, sizeof(*bss));
48
49 sfd = start_server(family, SOCK_STREAM,
50 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
51 if (!ASSERT_GE(sfd, 0, "start_server"))
52 return;
53
54 cfd = connect_to_fd(sfd, 0);
55 if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) {
56 close(sfd);
57 return;
58 }
59 close(sfd);
60 close(cfd);
61
62 ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
63 ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
64 ASSERT_EQ(bss->nr_active, 1, "nr_active");
65 ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
66 ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
67 ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
68 }
69
test_udp(int family)70 static void test_udp(int family)
71 {
72 struct setget_sockopt__bss *bss = skel->bss;
73 int sfd;
74
75 memset(bss, 0, sizeof(*bss));
76
77 sfd = start_server(family, SOCK_DGRAM,
78 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
79 if (!ASSERT_GE(sfd, 0, "start_server"))
80 return;
81 close(sfd);
82
83 ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create");
84 ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
85 }
86
test_ktls(int family)87 static void test_ktls(int family)
88 {
89 struct tls12_crypto_info_aes_gcm_128 aes128;
90 struct setget_sockopt__bss *bss = skel->bss;
91 int cfd = -1, sfd = -1, fd = -1, ret;
92 char buf;
93
94 memset(bss, 0, sizeof(*bss));
95
96 sfd = start_server(family, SOCK_STREAM,
97 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
98 if (!ASSERT_GE(sfd, 0, "start_server"))
99 return;
100 fd = connect_to_fd(sfd, 0);
101 if (!ASSERT_GE(fd, 0, "connect_to_fd"))
102 goto err_out;
103
104 cfd = accept(sfd, NULL, 0);
105 if (!ASSERT_GE(cfd, 0, "accept"))
106 goto err_out;
107
108 close(sfd);
109 sfd = -1;
110
111 /* Setup KTLS */
112 ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
113 if (!ASSERT_OK(ret, "setsockopt"))
114 goto err_out;
115 ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
116 if (!ASSERT_OK(ret, "setsockopt"))
117 goto err_out;
118
119 memset(&aes128, 0, sizeof(aes128));
120 aes128.info.version = TLS_1_2_VERSION;
121 aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128;
122
123 ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128));
124 if (!ASSERT_OK(ret, "setsockopt"))
125 goto err_out;
126
127 ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128));
128 if (!ASSERT_OK(ret, "setsockopt"))
129 goto err_out;
130
131 /* KTLS is enabled */
132
133 close(fd);
134 /* At this point, the cfd socket is at the CLOSE_WAIT state
135 * and still run TLS protocol. The test for
136 * BPF_TCP_CLOSE_WAIT should be run at this point.
137 */
138 ret = read(cfd, &buf, sizeof(buf));
139 ASSERT_EQ(ret, 0, "read");
140 close(cfd);
141
142 ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
143 ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
144 ASSERT_EQ(bss->nr_active, 1, "nr_active");
145 ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
146 ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
147 ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
148 ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1");
149 return;
150
151 err_out:
152 close(fd);
153 close(cfd);
154 close(sfd);
155 }
156
test_nonstandard_opt(int family)157 static void test_nonstandard_opt(int family)
158 {
159 struct setget_sockopt__bss *bss = skel->bss;
160 struct bpf_link *getsockopt_link = NULL;
161 int sfd = -1, fd = -1, cfd = -1, flags;
162 socklen_t flagslen = sizeof(flags);
163
164 memset(bss, 0, sizeof(*bss));
165
166 sfd = start_server(family, SOCK_STREAM,
167 family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
168 if (!ASSERT_GE(sfd, 0, "start_server"))
169 return;
170
171 fd = connect_to_fd(sfd, 0);
172 if (!ASSERT_GE(fd, 0, "connect_to_fd_server"))
173 goto err_out;
174
175 /* cgroup/getsockopt prog will intercept getsockopt() below and
176 * retrieve the tcp socket bpf_sock_ops_cb_flags value for the
177 * accept()ed socket; this was set earlier in the passive established
178 * callback for the accept()ed socket via bpf_setsockopt().
179 */
180 getsockopt_link = bpf_program__attach_cgroup(skel->progs._getsockopt, cg_fd);
181 if (!ASSERT_OK_PTR(getsockopt_link, "getsockopt prog"))
182 goto err_out;
183
184 cfd = accept(sfd, NULL, 0);
185 if (!ASSERT_GE(cfd, 0, "accept"))
186 goto err_out;
187
188 if (!ASSERT_OK(getsockopt(cfd, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, &flagslen),
189 "getsockopt_flags"))
190 goto err_out;
191 ASSERT_EQ(flags & BPF_SOCK_OPS_STATE_CB_FLAG, BPF_SOCK_OPS_STATE_CB_FLAG,
192 "cb_flags_set");
193 err_out:
194 close(sfd);
195 if (fd != -1)
196 close(fd);
197 if (cfd != -1)
198 close(cfd);
199 bpf_link__destroy(getsockopt_link);
200 }
201
test_setget_sockopt(void)202 void test_setget_sockopt(void)
203 {
204 cg_fd = test__join_cgroup(CG_NAME);
205 if (cg_fd < 0)
206 return;
207
208 if (create_netns())
209 goto done;
210
211 skel = setget_sockopt__open();
212 if (!ASSERT_OK_PTR(skel, "open skel"))
213 goto done;
214
215 strcpy(skel->rodata->veth, "binddevtest1");
216 skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
217 if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
218 goto done;
219
220 if (!ASSERT_OK(setget_sockopt__load(skel), "load skel"))
221 goto done;
222
223 skel->links.skops_sockopt =
224 bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
225 if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
226 goto done;
227
228 skel->links.socket_post_create =
229 bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd);
230 if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup"))
231 goto done;
232
233 test_tcp(AF_INET6);
234 test_tcp(AF_INET);
235 test_udp(AF_INET6);
236 test_udp(AF_INET);
237 test_ktls(AF_INET6);
238 test_ktls(AF_INET);
239 test_nonstandard_opt(AF_INET);
240 test_nonstandard_opt(AF_INET6);
241
242 done:
243 setget_sockopt__destroy(skel);
244 close(cg_fd);
245 }
246