brintos

brintos / linux-shallow public Read only

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