brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 501c3fc Raw
185 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <string.h>4 5#include <linux/stddef.h>6#include <linux/bpf.h>7#include <linux/in.h>8#include <linux/in6.h>9#include <linux/if.h>10#include <errno.h>11 12#include <bpf/bpf_helpers.h>13#include <bpf/bpf_endian.h>14 15#include "bind_prog.h"16 17#define SERV6_IP_0		0xfaceb00c /* face:b00c:1234:5678::abcd */18#define SERV6_IP_1		0x1234567819#define SERV6_IP_2		0x0000000020#define SERV6_IP_3		0x0000abcd21#define SERV6_PORT		606022#define SERV6_REWRITE_IP_0	0x0000000023#define SERV6_REWRITE_IP_1	0x0000000024#define SERV6_REWRITE_IP_2	0x0000000025#define SERV6_REWRITE_IP_3	0x0000000126#define SERV6_REWRITE_PORT	666627 28#ifndef IFNAMSIZ29#define IFNAMSIZ 1630#endif31 32static __inline int bind_to_device(struct bpf_sock_addr *ctx)33{34	char veth1[IFNAMSIZ] = "test_sock_addr1";35	char veth2[IFNAMSIZ] = "test_sock_addr2";36	char missing[IFNAMSIZ] = "nonexistent_dev";37	char del_bind[IFNAMSIZ] = "";38	int veth1_idx, veth2_idx;39 40	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,41			   &veth1, sizeof(veth1)))42		return 1;43	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,44			   &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)45		return 1;46	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,47			   &veth2, sizeof(veth2)))48		return 1;49	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,50			   &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||51	    veth1_idx == veth2_idx)52		return 1;53	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,54			   &missing, sizeof(missing)) != -ENODEV)55		return 1;56	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,57			   &veth1_idx, sizeof(veth1_idx)))58		return 1;59	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,60			   &del_bind, sizeof(del_bind)))61		return 1;62 63	return 0;64}65 66static __inline int bind_reuseport(struct bpf_sock_addr *ctx)67{68	int val = 1;69 70	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,71			   &val, sizeof(val)))72		return 1;73	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,74			   &val, sizeof(val)) || !val)75		return 1;76	val = 0;77	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,78			   &val, sizeof(val)))79		return 1;80	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,81			   &val, sizeof(val)) || val)82		return 1;83 84	return 0;85}86 87static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)88{89	int old, tmp, new = 0xeb9f;90 91	/* Socket in test case has guarantee that old never equals to new. */92	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||93	    old == new)94		return 1;95	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))96		return 1;97	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||98	    tmp != new)99		return 1;100	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))101		return 1;102 103	return 0;104}105 106SEC("cgroup/bind6")107int bind_v6_prog(struct bpf_sock_addr *ctx)108{109	struct bpf_sock *sk;110	__u32 user_ip6;111	__u16 user_port;112	int i;113 114	sk = ctx->sk;115	if (!sk)116		return 0;117 118	if (sk->family != AF_INET6)119		return 0;120 121	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)122		return 0;123 124	if (ctx->user_ip6[0] != bpf_htonl(SERV6_IP_0) ||125	    ctx->user_ip6[1] != bpf_htonl(SERV6_IP_1) ||126	    ctx->user_ip6[2] != bpf_htonl(SERV6_IP_2) ||127	    ctx->user_ip6[3] != bpf_htonl(SERV6_IP_3) ||128	    ctx->user_port != bpf_htons(SERV6_PORT))129		return 0;130 131	// u8 narrow loads:132	for (i = 0; i < 4; i++) {133		user_ip6 = 0;134		user_ip6 |= load_byte(ctx->user_ip6[i], 0, sizeof(user_ip6));135		user_ip6 |= load_byte(ctx->user_ip6[i], 1, sizeof(user_ip6));136		user_ip6 |= load_byte(ctx->user_ip6[i], 2, sizeof(user_ip6));137		user_ip6 |= load_byte(ctx->user_ip6[i], 3, sizeof(user_ip6));138		if (ctx->user_ip6[i] != user_ip6)139			return 0;140	}141 142	user_port = 0;143	user_port |= load_byte(ctx->user_port, 0, sizeof(user_port));144	user_port |= load_byte(ctx->user_port, 1, sizeof(user_port));145	if (ctx->user_port != user_port)146		return 0;147 148	// u16 narrow loads:149	for (i = 0; i < 4; i++) {150		user_ip6 = 0;151		user_ip6 |= load_word(ctx->user_ip6[i], 0, sizeof(user_ip6));152		user_ip6 |= load_word(ctx->user_ip6[i], 1, sizeof(user_ip6));153		if (ctx->user_ip6[i] != user_ip6)154			return 0;155	}156 157	/* Bind to device and unbind it. */158	if (bind_to_device(ctx))159		return 0;160 161	/* Test for misc socket options. */162	if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))163		return 0;164 165	/* Set reuseport and unset */166	if (bind_reuseport(ctx))167		return 0;168 169	ctx->user_ip6[0] = bpf_htonl(SERV6_REWRITE_IP_0);170	ctx->user_ip6[1] = bpf_htonl(SERV6_REWRITE_IP_1);171	ctx->user_ip6[2] = bpf_htonl(SERV6_REWRITE_IP_2);172	ctx->user_ip6[3] = bpf_htonl(SERV6_REWRITE_IP_3);173	ctx->user_port = bpf_htons(SERV6_REWRITE_PORT);174 175	return 1;176}177 178SEC("cgroup/bind6")179int bind_v6_deny_prog(struct bpf_sock_addr *ctx)180{181	return 0;182}183 184char _license[] SEC("license") = "GPL";185