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 <sys/socket.h>
10 #include <netinet/tcp.h>
11 #include <linux/if.h>
12 #include <errno.h>
13 
14 #include <bpf/bpf_helpers.h>
15 #include <bpf/bpf_endian.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 
26 static __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 
33 	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
34 				&veth1, sizeof(veth1)))
35 		return 1;
36 	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
37 				&veth2, sizeof(veth2)))
38 		return 1;
39 	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
40 				&missing, sizeof(missing)) != -ENODEV)
41 		return 1;
42 	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
43 				&del_bind, sizeof(del_bind)))
44 		return 1;
45 
46 	return 0;
47 }
48 
49 SEC("cgroup/bind4")
50 int bind_v4_prog(struct bpf_sock_addr *ctx)
51 {
52 	struct bpf_sock *sk;
53 	__u32 user_ip4;
54 	__u16 user_port;
55 
56 	sk = ctx->sk;
57 	if (!sk)
58 		return 0;
59 
60 	if (sk->family != AF_INET)
61 		return 0;
62 
63 	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
64 		return 0;
65 
66 	if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||
67 	    ctx->user_port != bpf_htons(SERV4_PORT))
68 		return 0;
69 
70 	// u8 narrow loads:
71 	user_ip4 = 0;
72 	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0;
73 	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8;
74 	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16;
75 	user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24;
76 	if (ctx->user_ip4 != user_ip4)
77 		return 0;
78 
79 	user_port = 0;
80 	user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
81 	user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
82 	if (ctx->user_port != user_port)
83 		return 0;
84 
85 	// u16 narrow loads:
86 	user_ip4 = 0;
87 	user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0;
88 	user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16;
89 	if (ctx->user_ip4 != user_ip4)
90 		return 0;
91 
92 	/* Bind to device and unbind it. */
93 	if (bind_to_device(ctx))
94 		return 0;
95 
96 	ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);
97 	ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);
98 
99 	return 1;
100 }
101 
102 char _license[] SEC("license") = "GPL";
103