Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0
  2
  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#define SERV4_IP		0xc0a801feU /* 192.168.1.254 */
 16#define SERV4_PORT		4040
 17#define SERV4_REWRITE_IP	0x7f000001U /* 127.0.0.1 */
 18#define SERV4_REWRITE_PORT	4444
 19
 20#ifndef IFNAMSIZ
 21#define IFNAMSIZ 16
 22#endif
 23
 24static __inline int bind_to_device(struct bpf_sock_addr *ctx)
 25{
 26	char veth1[IFNAMSIZ] = "test_sock_addr1";
 27	char veth2[IFNAMSIZ] = "test_sock_addr2";
 28	char missing[IFNAMSIZ] = "nonexistent_dev";
 29	char del_bind[IFNAMSIZ] = "";
 30	int veth1_idx, veth2_idx;
 31
 32	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
 33			   &veth1, sizeof(veth1)))
 34		return 1;
 35	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
 36			   &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)
 37		return 1;
 38	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
 39			   &veth2, sizeof(veth2)))
 40		return 1;
 41	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
 42			   &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||
 43	    veth1_idx == veth2_idx)
 44		return 1;
 45	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
 46			   &missing, sizeof(missing)) != -ENODEV)
 47		return 1;
 48	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
 49			   &veth1_idx, sizeof(veth1_idx)))
 50		return 1;
 51	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
 52			   &del_bind, sizeof(del_bind)))
 53		return 1;
 54
 55	return 0;
 56}
 57
 58static __inline int bind_reuseport(struct bpf_sock_addr *ctx)
 59{
 60	int val = 1;
 61
 62	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
 63			   &val, sizeof(val)))
 64		return 1;
 65	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
 66			   &val, sizeof(val)) || !val)
 67		return 1;
 68	val = 0;
 69	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
 70			   &val, sizeof(val)))
 71		return 1;
 72	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
 73			   &val, sizeof(val)) || val)
 74		return 1;
 75
 76	return 0;
 77}
 78
 79static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)
 80{
 81	int old, tmp, new = 0xeb9f;
 82
 83	/* Socket in test case has guarantee that old never equals to new. */
 84	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||
 85	    old == new)
 86		return 1;
 87	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))
 88		return 1;
 89	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||
 90	    tmp != new)
 91		return 1;
 92	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))
 93		return 1;
 94
 95	return 0;
 96}
 97
 98SEC("cgroup/bind4")
 99int bind_v4_prog(struct bpf_sock_addr *ctx)
100{
101	struct bpf_sock *sk;
102	__u32 user_ip4;
103	__u16 user_port;
104
105	sk = ctx->sk;
106	if (!sk)
107		return 0;
108
109	if (sk->family != AF_INET)
110		return 0;
111
112	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
113		return 0;
114
115	if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||
116	    ctx->user_port != bpf_htons(SERV4_PORT))
117		return 0;
118
119	// u8 narrow loads:
120	user_ip4 = 0;
121	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0;
122	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8;
123	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16;
124	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24;
125	if (ctx->user_ip4 != user_ip4)
126		return 0;
127
128	user_port = 0;
129	user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
130	user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
131	if (ctx->user_port != user_port)
132		return 0;
133
134	// u16 narrow loads:
135	user_ip4 = 0;
136	user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0;
137	user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16;
138	if (ctx->user_ip4 != user_ip4)
139		return 0;
140
141	/* Bind to device and unbind it. */
142	if (bind_to_device(ctx))
143		return 0;
144
145	/* Test for misc socket options. */
146	if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
147		return 0;
148
149	/* Set reuseport and unset */
150	if (bind_reuseport(ctx))
151		return 0;
152
153	ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);
154	ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);
155
156	return 1;
157}
158
159char _license[] SEC("license") = "GPL";