1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 // Copyright (c) 2020 Cloudflare
3 
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <linux/bpf.h>
8 #include <linux/in.h>
9 #include <sys/socket.h>
10 
11 #include <bpf/bpf_endian.h>
12 #include <bpf/bpf_helpers.h>
13 
14 #define IP4(a, b, c, d)					\
15 	bpf_htonl((((__u32)(a) & 0xffU) << 24) |	\
16 		  (((__u32)(b) & 0xffU) << 16) |	\
17 		  (((__u32)(c) & 0xffU) <<  8) |	\
18 		  (((__u32)(d) & 0xffU) <<  0))
19 #define IP6(aaaa, bbbb, cccc, dddd)			\
20 	{ bpf_htonl(aaaa), bpf_htonl(bbbb), bpf_htonl(cccc), bpf_htonl(dddd) }
21 
22 /* Macros for least-significant byte and word accesses. */
23 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
24 #define LSE_INDEX(index, size) (index)
25 #else
26 #define LSE_INDEX(index, size) ((size) - (index) - 1)
27 #endif
28 #define LSB(value, index)				\
29 	(((__u8 *)&(value))[LSE_INDEX((index), sizeof(value))])
30 #define LSW(value, index)				\
31 	(((__u16 *)&(value))[LSE_INDEX((index), sizeof(value) / 2)])
32 
33 #define MAX_SOCKS 32
34 
35 struct {
36 	__uint(type, BPF_MAP_TYPE_SOCKMAP);
37 	__uint(max_entries, MAX_SOCKS);
38 	__type(key, __u32);
39 	__type(value, __u64);
40 } redir_map SEC(".maps");
41 
42 struct {
43 	__uint(type, BPF_MAP_TYPE_ARRAY);
44 	__uint(max_entries, 2);
45 	__type(key, int);
46 	__type(value, int);
47 } run_map SEC(".maps");
48 
49 enum {
50 	PROG1 = 0,
51 	PROG2,
52 };
53 
54 enum {
55 	SERVER_A = 0,
56 	SERVER_B,
57 };
58 
59 /* Addressable key/value constants for convenience */
60 static const int KEY_PROG1 = PROG1;
61 static const int KEY_PROG2 = PROG2;
62 static const int PROG_DONE = 1;
63 
64 static const __u32 KEY_SERVER_A = SERVER_A;
65 static const __u32 KEY_SERVER_B = SERVER_B;
66 
67 static const __u16 DST_PORT = 7007; /* Host byte order */
68 static const __u32 DST_IP4 = IP4(127, 0, 0, 1);
69 static const __u32 DST_IP6[] = IP6(0xfd000000, 0x0, 0x0, 0x00000001);
70 
71 SEC("sk_lookup/lookup_pass")
lookup_pass(struct bpf_sk_lookup * ctx)72 int lookup_pass(struct bpf_sk_lookup *ctx)
73 {
74 	return SK_PASS;
75 }
76 
77 SEC("sk_lookup/lookup_drop")
lookup_drop(struct bpf_sk_lookup * ctx)78 int lookup_drop(struct bpf_sk_lookup *ctx)
79 {
80 	return SK_DROP;
81 }
82 
83 SEC("sk_reuseport/reuse_pass")
reuseport_pass(struct sk_reuseport_md * ctx)84 int reuseport_pass(struct sk_reuseport_md *ctx)
85 {
86 	return SK_PASS;
87 }
88 
89 SEC("sk_reuseport/reuse_drop")
reuseport_drop(struct sk_reuseport_md * ctx)90 int reuseport_drop(struct sk_reuseport_md *ctx)
91 {
92 	return SK_DROP;
93 }
94 
95 /* Redirect packets destined for port DST_PORT to socket at redir_map[0]. */
96 SEC("sk_lookup/redir_port")
redir_port(struct bpf_sk_lookup * ctx)97 int redir_port(struct bpf_sk_lookup *ctx)
98 {
99 	struct bpf_sock *sk;
100 	int err;
101 
102 	if (ctx->local_port != DST_PORT)
103 		return SK_PASS;
104 
105 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
106 	if (!sk)
107 		return SK_PASS;
108 
109 	err = bpf_sk_assign(ctx, sk, 0);
110 	bpf_sk_release(sk);
111 	return err ? SK_DROP : SK_PASS;
112 }
113 
114 /* Redirect packets destined for DST_IP4 address to socket at redir_map[0]. */
115 SEC("sk_lookup/redir_ip4")
redir_ip4(struct bpf_sk_lookup * ctx)116 int redir_ip4(struct bpf_sk_lookup *ctx)
117 {
118 	struct bpf_sock *sk;
119 	int err;
120 
121 	if (ctx->family != AF_INET)
122 		return SK_PASS;
123 	if (ctx->local_port != DST_PORT)
124 		return SK_PASS;
125 	if (ctx->local_ip4 != DST_IP4)
126 		return SK_PASS;
127 
128 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
129 	if (!sk)
130 		return SK_PASS;
131 
132 	err = bpf_sk_assign(ctx, sk, 0);
133 	bpf_sk_release(sk);
134 	return err ? SK_DROP : SK_PASS;
135 }
136 
137 /* Redirect packets destined for DST_IP6 address to socket at redir_map[0]. */
138 SEC("sk_lookup/redir_ip6")
redir_ip6(struct bpf_sk_lookup * ctx)139 int redir_ip6(struct bpf_sk_lookup *ctx)
140 {
141 	struct bpf_sock *sk;
142 	int err;
143 
144 	if (ctx->family != AF_INET6)
145 		return SK_PASS;
146 	if (ctx->local_port != DST_PORT)
147 		return SK_PASS;
148 	if (ctx->local_ip6[0] != DST_IP6[0] ||
149 	    ctx->local_ip6[1] != DST_IP6[1] ||
150 	    ctx->local_ip6[2] != DST_IP6[2] ||
151 	    ctx->local_ip6[3] != DST_IP6[3])
152 		return SK_PASS;
153 
154 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
155 	if (!sk)
156 		return SK_PASS;
157 
158 	err = bpf_sk_assign(ctx, sk, 0);
159 	bpf_sk_release(sk);
160 	return err ? SK_DROP : SK_PASS;
161 }
162 
163 SEC("sk_lookup/select_sock_a")
select_sock_a(struct bpf_sk_lookup * ctx)164 int select_sock_a(struct bpf_sk_lookup *ctx)
165 {
166 	struct bpf_sock *sk;
167 	int err;
168 
169 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
170 	if (!sk)
171 		return SK_PASS;
172 
173 	err = bpf_sk_assign(ctx, sk, 0);
174 	bpf_sk_release(sk);
175 	return err ? SK_DROP : SK_PASS;
176 }
177 
178 SEC("sk_lookup/select_sock_a_no_reuseport")
select_sock_a_no_reuseport(struct bpf_sk_lookup * ctx)179 int select_sock_a_no_reuseport(struct bpf_sk_lookup *ctx)
180 {
181 	struct bpf_sock *sk;
182 	int err;
183 
184 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
185 	if (!sk)
186 		return SK_DROP;
187 
188 	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_NO_REUSEPORT);
189 	bpf_sk_release(sk);
190 	return err ? SK_DROP : SK_PASS;
191 }
192 
193 SEC("sk_reuseport/select_sock_b")
select_sock_b(struct sk_reuseport_md * ctx)194 int select_sock_b(struct sk_reuseport_md *ctx)
195 {
196 	__u32 key = KEY_SERVER_B;
197 	int err;
198 
199 	err = bpf_sk_select_reuseport(ctx, &redir_map, &key, 0);
200 	return err ? SK_DROP : SK_PASS;
201 }
202 
203 /* Check that bpf_sk_assign() returns -EEXIST if socket already selected. */
204 SEC("sk_lookup/sk_assign_eexist")
sk_assign_eexist(struct bpf_sk_lookup * ctx)205 int sk_assign_eexist(struct bpf_sk_lookup *ctx)
206 {
207 	struct bpf_sock *sk;
208 	int err, ret;
209 
210 	ret = SK_DROP;
211 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
212 	if (!sk)
213 		goto out;
214 	err = bpf_sk_assign(ctx, sk, 0);
215 	if (err)
216 		goto out;
217 	bpf_sk_release(sk);
218 
219 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
220 	if (!sk)
221 		goto out;
222 	err = bpf_sk_assign(ctx, sk, 0);
223 	if (err != -EEXIST) {
224 		bpf_printk("sk_assign returned %d, expected %d\n",
225 			   err, -EEXIST);
226 		goto out;
227 	}
228 
229 	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
230 out:
231 	if (sk)
232 		bpf_sk_release(sk);
233 	return ret;
234 }
235 
236 /* Check that bpf_sk_assign(BPF_SK_LOOKUP_F_REPLACE) can override selection. */
237 SEC("sk_lookup/sk_assign_replace_flag")
sk_assign_replace_flag(struct bpf_sk_lookup * ctx)238 int sk_assign_replace_flag(struct bpf_sk_lookup *ctx)
239 {
240 	struct bpf_sock *sk;
241 	int err, ret;
242 
243 	ret = SK_DROP;
244 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
245 	if (!sk)
246 		goto out;
247 	err = bpf_sk_assign(ctx, sk, 0);
248 	if (err)
249 		goto out;
250 	bpf_sk_release(sk);
251 
252 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
253 	if (!sk)
254 		goto out;
255 	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
256 	if (err) {
257 		bpf_printk("sk_assign returned %d, expected 0\n", err);
258 		goto out;
259 	}
260 
261 	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
262 out:
263 	if (sk)
264 		bpf_sk_release(sk);
265 	return ret;
266 }
267 
268 /* Check that bpf_sk_assign(sk=NULL) is accepted. */
269 SEC("sk_lookup/sk_assign_null")
sk_assign_null(struct bpf_sk_lookup * ctx)270 int sk_assign_null(struct bpf_sk_lookup *ctx)
271 {
272 	struct bpf_sock *sk = NULL;
273 	int err, ret;
274 
275 	ret = SK_DROP;
276 
277 	err = bpf_sk_assign(ctx, NULL, 0);
278 	if (err) {
279 		bpf_printk("sk_assign returned %d, expected 0\n", err);
280 		goto out;
281 	}
282 
283 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
284 	if (!sk)
285 		goto out;
286 	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
287 	if (err) {
288 		bpf_printk("sk_assign returned %d, expected 0\n", err);
289 		goto out;
290 	}
291 
292 	if (ctx->sk != sk)
293 		goto out;
294 	err = bpf_sk_assign(ctx, NULL, 0);
295 	if (err != -EEXIST)
296 		goto out;
297 	err = bpf_sk_assign(ctx, NULL, BPF_SK_LOOKUP_F_REPLACE);
298 	if (err)
299 		goto out;
300 	err = bpf_sk_assign(ctx, sk, BPF_SK_LOOKUP_F_REPLACE);
301 	if (err)
302 		goto out;
303 
304 	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
305 out:
306 	if (sk)
307 		bpf_sk_release(sk);
308 	return ret;
309 }
310 
311 /* Check that selected sk is accessible through context. */
312 SEC("sk_lookup/access_ctx_sk")
access_ctx_sk(struct bpf_sk_lookup * ctx)313 int access_ctx_sk(struct bpf_sk_lookup *ctx)
314 {
315 	struct bpf_sock *sk1 = NULL, *sk2 = NULL;
316 	int err, ret;
317 
318 	ret = SK_DROP;
319 
320 	/* Try accessing unassigned (NULL) ctx->sk field */
321 	if (ctx->sk && ctx->sk->family != AF_INET)
322 		goto out;
323 
324 	/* Assign a value to ctx->sk */
325 	sk1 = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
326 	if (!sk1)
327 		goto out;
328 	err = bpf_sk_assign(ctx, sk1, 0);
329 	if (err)
330 		goto out;
331 	if (ctx->sk != sk1)
332 		goto out;
333 
334 	/* Access ctx->sk fields */
335 	if (ctx->sk->family != AF_INET ||
336 	    ctx->sk->type != SOCK_STREAM ||
337 	    ctx->sk->state != BPF_TCP_LISTEN)
338 		goto out;
339 
340 	/* Reset selection */
341 	err = bpf_sk_assign(ctx, NULL, BPF_SK_LOOKUP_F_REPLACE);
342 	if (err)
343 		goto out;
344 	if (ctx->sk)
345 		goto out;
346 
347 	/* Assign another socket */
348 	sk2 = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
349 	if (!sk2)
350 		goto out;
351 	err = bpf_sk_assign(ctx, sk2, BPF_SK_LOOKUP_F_REPLACE);
352 	if (err)
353 		goto out;
354 	if (ctx->sk != sk2)
355 		goto out;
356 
357 	/* Access reassigned ctx->sk fields */
358 	if (ctx->sk->family != AF_INET ||
359 	    ctx->sk->type != SOCK_STREAM ||
360 	    ctx->sk->state != BPF_TCP_LISTEN)
361 		goto out;
362 
363 	ret = SK_PASS; /* Success, redirect to KEY_SERVER_B */
364 out:
365 	if (sk1)
366 		bpf_sk_release(sk1);
367 	if (sk2)
368 		bpf_sk_release(sk2);
369 	return ret;
370 }
371 
372 /* Check narrow loads from ctx fields that support them.
373  *
374  * Narrow loads of size >= target field size from a non-zero offset
375  * are not covered because they give bogus results, that is the
376  * verifier ignores the offset.
377  */
378 SEC("sk_lookup/ctx_narrow_access")
ctx_narrow_access(struct bpf_sk_lookup * ctx)379 int ctx_narrow_access(struct bpf_sk_lookup *ctx)
380 {
381 	struct bpf_sock *sk;
382 	int err, family;
383 	bool v4;
384 
385 	v4 = (ctx->family == AF_INET);
386 
387 	/* Narrow loads from family field */
388 	if (LSB(ctx->family, 0) != (v4 ? AF_INET : AF_INET6) ||
389 	    LSB(ctx->family, 1) != 0 || LSB(ctx->family, 2) != 0 || LSB(ctx->family, 3) != 0)
390 		return SK_DROP;
391 	if (LSW(ctx->family, 0) != (v4 ? AF_INET : AF_INET6))
392 		return SK_DROP;
393 
394 	/* Narrow loads from protocol field */
395 	if (LSB(ctx->protocol, 0) != IPPROTO_TCP ||
396 	    LSB(ctx->protocol, 1) != 0 || LSB(ctx->protocol, 2) != 0 || LSB(ctx->protocol, 3) != 0)
397 		return SK_DROP;
398 	if (LSW(ctx->protocol, 0) != IPPROTO_TCP)
399 		return SK_DROP;
400 
401 	/* Narrow loads from remote_port field. Expect non-0 value. */
402 	if (LSB(ctx->remote_port, 0) == 0 && LSB(ctx->remote_port, 1) == 0 &&
403 	    LSB(ctx->remote_port, 2) == 0 && LSB(ctx->remote_port, 3) == 0)
404 		return SK_DROP;
405 	if (LSW(ctx->remote_port, 0) == 0)
406 		return SK_DROP;
407 
408 	/* Narrow loads from local_port field. Expect DST_PORT. */
409 	if (LSB(ctx->local_port, 0) != ((DST_PORT >> 0) & 0xff) ||
410 	    LSB(ctx->local_port, 1) != ((DST_PORT >> 8) & 0xff) ||
411 	    LSB(ctx->local_port, 2) != 0 || LSB(ctx->local_port, 3) != 0)
412 		return SK_DROP;
413 	if (LSW(ctx->local_port, 0) != DST_PORT)
414 		return SK_DROP;
415 
416 	/* Narrow loads from IPv4 fields */
417 	if (v4) {
418 		/* Expect non-0.0.0.0 in remote_ip4 */
419 		if (LSB(ctx->remote_ip4, 0) == 0 && LSB(ctx->remote_ip4, 1) == 0 &&
420 		    LSB(ctx->remote_ip4, 2) == 0 && LSB(ctx->remote_ip4, 3) == 0)
421 			return SK_DROP;
422 		if (LSW(ctx->remote_ip4, 0) == 0 && LSW(ctx->remote_ip4, 1) == 0)
423 			return SK_DROP;
424 
425 		/* Expect DST_IP4 in local_ip4 */
426 		if (LSB(ctx->local_ip4, 0) != ((DST_IP4 >> 0) & 0xff) ||
427 		    LSB(ctx->local_ip4, 1) != ((DST_IP4 >> 8) & 0xff) ||
428 		    LSB(ctx->local_ip4, 2) != ((DST_IP4 >> 16) & 0xff) ||
429 		    LSB(ctx->local_ip4, 3) != ((DST_IP4 >> 24) & 0xff))
430 			return SK_DROP;
431 		if (LSW(ctx->local_ip4, 0) != ((DST_IP4 >> 0) & 0xffff) ||
432 		    LSW(ctx->local_ip4, 1) != ((DST_IP4 >> 16) & 0xffff))
433 			return SK_DROP;
434 	} else {
435 		/* Expect 0.0.0.0 IPs when family != AF_INET */
436 		if (LSB(ctx->remote_ip4, 0) != 0 || LSB(ctx->remote_ip4, 1) != 0 ||
437 		    LSB(ctx->remote_ip4, 2) != 0 || LSB(ctx->remote_ip4, 3) != 0)
438 			return SK_DROP;
439 		if (LSW(ctx->remote_ip4, 0) != 0 || LSW(ctx->remote_ip4, 1) != 0)
440 			return SK_DROP;
441 
442 		if (LSB(ctx->local_ip4, 0) != 0 || LSB(ctx->local_ip4, 1) != 0 ||
443 		    LSB(ctx->local_ip4, 2) != 0 || LSB(ctx->local_ip4, 3) != 0)
444 			return SK_DROP;
445 		if (LSW(ctx->local_ip4, 0) != 0 || LSW(ctx->local_ip4, 1) != 0)
446 			return SK_DROP;
447 	}
448 
449 	/* Narrow loads from IPv6 fields */
450 	if (!v4) {
451 		/* Expect non-:: IP in remote_ip6 */
452 		if (LSB(ctx->remote_ip6[0], 0) == 0 && LSB(ctx->remote_ip6[0], 1) == 0 &&
453 		    LSB(ctx->remote_ip6[0], 2) == 0 && LSB(ctx->remote_ip6[0], 3) == 0 &&
454 		    LSB(ctx->remote_ip6[1], 0) == 0 && LSB(ctx->remote_ip6[1], 1) == 0 &&
455 		    LSB(ctx->remote_ip6[1], 2) == 0 && LSB(ctx->remote_ip6[1], 3) == 0 &&
456 		    LSB(ctx->remote_ip6[2], 0) == 0 && LSB(ctx->remote_ip6[2], 1) == 0 &&
457 		    LSB(ctx->remote_ip6[2], 2) == 0 && LSB(ctx->remote_ip6[2], 3) == 0 &&
458 		    LSB(ctx->remote_ip6[3], 0) == 0 && LSB(ctx->remote_ip6[3], 1) == 0 &&
459 		    LSB(ctx->remote_ip6[3], 2) == 0 && LSB(ctx->remote_ip6[3], 3) == 0)
460 			return SK_DROP;
461 		if (LSW(ctx->remote_ip6[0], 0) == 0 && LSW(ctx->remote_ip6[0], 1) == 0 &&
462 		    LSW(ctx->remote_ip6[1], 0) == 0 && LSW(ctx->remote_ip6[1], 1) == 0 &&
463 		    LSW(ctx->remote_ip6[2], 0) == 0 && LSW(ctx->remote_ip6[2], 1) == 0 &&
464 		    LSW(ctx->remote_ip6[3], 0) == 0 && LSW(ctx->remote_ip6[3], 1) == 0)
465 			return SK_DROP;
466 		/* Expect DST_IP6 in local_ip6 */
467 		if (LSB(ctx->local_ip6[0], 0) != ((DST_IP6[0] >> 0) & 0xff) ||
468 		    LSB(ctx->local_ip6[0], 1) != ((DST_IP6[0] >> 8) & 0xff) ||
469 		    LSB(ctx->local_ip6[0], 2) != ((DST_IP6[0] >> 16) & 0xff) ||
470 		    LSB(ctx->local_ip6[0], 3) != ((DST_IP6[0] >> 24) & 0xff) ||
471 		    LSB(ctx->local_ip6[1], 0) != ((DST_IP6[1] >> 0) & 0xff) ||
472 		    LSB(ctx->local_ip6[1], 1) != ((DST_IP6[1] >> 8) & 0xff) ||
473 		    LSB(ctx->local_ip6[1], 2) != ((DST_IP6[1] >> 16) & 0xff) ||
474 		    LSB(ctx->local_ip6[1], 3) != ((DST_IP6[1] >> 24) & 0xff) ||
475 		    LSB(ctx->local_ip6[2], 0) != ((DST_IP6[2] >> 0) & 0xff) ||
476 		    LSB(ctx->local_ip6[2], 1) != ((DST_IP6[2] >> 8) & 0xff) ||
477 		    LSB(ctx->local_ip6[2], 2) != ((DST_IP6[2] >> 16) & 0xff) ||
478 		    LSB(ctx->local_ip6[2], 3) != ((DST_IP6[2] >> 24) & 0xff) ||
479 		    LSB(ctx->local_ip6[3], 0) != ((DST_IP6[3] >> 0) & 0xff) ||
480 		    LSB(ctx->local_ip6[3], 1) != ((DST_IP6[3] >> 8) & 0xff) ||
481 		    LSB(ctx->local_ip6[3], 2) != ((DST_IP6[3] >> 16) & 0xff) ||
482 		    LSB(ctx->local_ip6[3], 3) != ((DST_IP6[3] >> 24) & 0xff))
483 			return SK_DROP;
484 		if (LSW(ctx->local_ip6[0], 0) != ((DST_IP6[0] >> 0) & 0xffff) ||
485 		    LSW(ctx->local_ip6[0], 1) != ((DST_IP6[0] >> 16) & 0xffff) ||
486 		    LSW(ctx->local_ip6[1], 0) != ((DST_IP6[1] >> 0) & 0xffff) ||
487 		    LSW(ctx->local_ip6[1], 1) != ((DST_IP6[1] >> 16) & 0xffff) ||
488 		    LSW(ctx->local_ip6[2], 0) != ((DST_IP6[2] >> 0) & 0xffff) ||
489 		    LSW(ctx->local_ip6[2], 1) != ((DST_IP6[2] >> 16) & 0xffff) ||
490 		    LSW(ctx->local_ip6[3], 0) != ((DST_IP6[3] >> 0) & 0xffff) ||
491 		    LSW(ctx->local_ip6[3], 1) != ((DST_IP6[3] >> 16) & 0xffff))
492 			return SK_DROP;
493 	} else {
494 		/* Expect :: IPs when family != AF_INET6 */
495 		if (LSB(ctx->remote_ip6[0], 0) != 0 || LSB(ctx->remote_ip6[0], 1) != 0 ||
496 		    LSB(ctx->remote_ip6[0], 2) != 0 || LSB(ctx->remote_ip6[0], 3) != 0 ||
497 		    LSB(ctx->remote_ip6[1], 0) != 0 || LSB(ctx->remote_ip6[1], 1) != 0 ||
498 		    LSB(ctx->remote_ip6[1], 2) != 0 || LSB(ctx->remote_ip6[1], 3) != 0 ||
499 		    LSB(ctx->remote_ip6[2], 0) != 0 || LSB(ctx->remote_ip6[2], 1) != 0 ||
500 		    LSB(ctx->remote_ip6[2], 2) != 0 || LSB(ctx->remote_ip6[2], 3) != 0 ||
501 		    LSB(ctx->remote_ip6[3], 0) != 0 || LSB(ctx->remote_ip6[3], 1) != 0 ||
502 		    LSB(ctx->remote_ip6[3], 2) != 0 || LSB(ctx->remote_ip6[3], 3) != 0)
503 			return SK_DROP;
504 		if (LSW(ctx->remote_ip6[0], 0) != 0 || LSW(ctx->remote_ip6[0], 1) != 0 ||
505 		    LSW(ctx->remote_ip6[1], 0) != 0 || LSW(ctx->remote_ip6[1], 1) != 0 ||
506 		    LSW(ctx->remote_ip6[2], 0) != 0 || LSW(ctx->remote_ip6[2], 1) != 0 ||
507 		    LSW(ctx->remote_ip6[3], 0) != 0 || LSW(ctx->remote_ip6[3], 1) != 0)
508 			return SK_DROP;
509 
510 		if (LSB(ctx->local_ip6[0], 0) != 0 || LSB(ctx->local_ip6[0], 1) != 0 ||
511 		    LSB(ctx->local_ip6[0], 2) != 0 || LSB(ctx->local_ip6[0], 3) != 0 ||
512 		    LSB(ctx->local_ip6[1], 0) != 0 || LSB(ctx->local_ip6[1], 1) != 0 ||
513 		    LSB(ctx->local_ip6[1], 2) != 0 || LSB(ctx->local_ip6[1], 3) != 0 ||
514 		    LSB(ctx->local_ip6[2], 0) != 0 || LSB(ctx->local_ip6[2], 1) != 0 ||
515 		    LSB(ctx->local_ip6[2], 2) != 0 || LSB(ctx->local_ip6[2], 3) != 0 ||
516 		    LSB(ctx->local_ip6[3], 0) != 0 || LSB(ctx->local_ip6[3], 1) != 0 ||
517 		    LSB(ctx->local_ip6[3], 2) != 0 || LSB(ctx->local_ip6[3], 3) != 0)
518 			return SK_DROP;
519 		if (LSW(ctx->remote_ip6[0], 0) != 0 || LSW(ctx->remote_ip6[0], 1) != 0 ||
520 		    LSW(ctx->remote_ip6[1], 0) != 0 || LSW(ctx->remote_ip6[1], 1) != 0 ||
521 		    LSW(ctx->remote_ip6[2], 0) != 0 || LSW(ctx->remote_ip6[2], 1) != 0 ||
522 		    LSW(ctx->remote_ip6[3], 0) != 0 || LSW(ctx->remote_ip6[3], 1) != 0)
523 			return SK_DROP;
524 	}
525 
526 	/* Success, redirect to KEY_SERVER_B */
527 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_B);
528 	if (sk) {
529 		bpf_sk_assign(ctx, sk, 0);
530 		bpf_sk_release(sk);
531 	}
532 	return SK_PASS;
533 }
534 
535 /* Check that sk_assign rejects SERVER_A socket with -ESOCKNOSUPPORT */
536 SEC("sk_lookup/sk_assign_esocknosupport")
sk_assign_esocknosupport(struct bpf_sk_lookup * ctx)537 int sk_assign_esocknosupport(struct bpf_sk_lookup *ctx)
538 {
539 	struct bpf_sock *sk;
540 	int err, ret;
541 
542 	ret = SK_DROP;
543 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
544 	if (!sk)
545 		goto out;
546 
547 	err = bpf_sk_assign(ctx, sk, 0);
548 	if (err != -ESOCKTNOSUPPORT) {
549 		bpf_printk("sk_assign returned %d, expected %d\n",
550 			   err, -ESOCKTNOSUPPORT);
551 		goto out;
552 	}
553 
554 	ret = SK_PASS; /* Success, pass to regular lookup */
555 out:
556 	if (sk)
557 		bpf_sk_release(sk);
558 	return ret;
559 }
560 
561 SEC("sk_lookup/multi_prog_pass1")
multi_prog_pass1(struct bpf_sk_lookup * ctx)562 int multi_prog_pass1(struct bpf_sk_lookup *ctx)
563 {
564 	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
565 	return SK_PASS;
566 }
567 
568 SEC("sk_lookup/multi_prog_pass2")
multi_prog_pass2(struct bpf_sk_lookup * ctx)569 int multi_prog_pass2(struct bpf_sk_lookup *ctx)
570 {
571 	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
572 	return SK_PASS;
573 }
574 
575 SEC("sk_lookup/multi_prog_drop1")
multi_prog_drop1(struct bpf_sk_lookup * ctx)576 int multi_prog_drop1(struct bpf_sk_lookup *ctx)
577 {
578 	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
579 	return SK_DROP;
580 }
581 
582 SEC("sk_lookup/multi_prog_drop2")
multi_prog_drop2(struct bpf_sk_lookup * ctx)583 int multi_prog_drop2(struct bpf_sk_lookup *ctx)
584 {
585 	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
586 	return SK_DROP;
587 }
588 
select_server_a(struct bpf_sk_lookup * ctx)589 static __always_inline int select_server_a(struct bpf_sk_lookup *ctx)
590 {
591 	struct bpf_sock *sk;
592 	int err;
593 
594 	sk = bpf_map_lookup_elem(&redir_map, &KEY_SERVER_A);
595 	if (!sk)
596 		return SK_DROP;
597 
598 	err = bpf_sk_assign(ctx, sk, 0);
599 	bpf_sk_release(sk);
600 	if (err)
601 		return SK_DROP;
602 
603 	return SK_PASS;
604 }
605 
606 SEC("sk_lookup/multi_prog_redir1")
multi_prog_redir1(struct bpf_sk_lookup * ctx)607 int multi_prog_redir1(struct bpf_sk_lookup *ctx)
608 {
609 	int ret;
610 
611 	ret = select_server_a(ctx);
612 	bpf_map_update_elem(&run_map, &KEY_PROG1, &PROG_DONE, BPF_ANY);
613 	return SK_PASS;
614 }
615 
616 SEC("sk_lookup/multi_prog_redir2")
multi_prog_redir2(struct bpf_sk_lookup * ctx)617 int multi_prog_redir2(struct bpf_sk_lookup *ctx)
618 {
619 	int ret;
620 
621 	ret = select_server_a(ctx);
622 	bpf_map_update_elem(&run_map, &KEY_PROG2, &PROG_DONE, BPF_ANY);
623 	return SK_PASS;
624 }
625 
626 char _license[] SEC("license") = "Dual BSD/GPL";
627 __u32 _version SEC("version") = 1;
628