Linux Audio

Check our new training course

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