1bd4aed0eSJiong Wang // SPDX-License-Identifier: GPL-2.0
2bd4aed0eSJiong Wang // Copyright (c) 2018 Facebook
3bd4aed0eSJiong Wang 
4bd4aed0eSJiong Wang #include <string.h>
5bd4aed0eSJiong Wang 
6bd4aed0eSJiong Wang #include <linux/stddef.h>
7bd4aed0eSJiong Wang #include <linux/bpf.h>
8bd4aed0eSJiong Wang #include <linux/in.h>
9bd4aed0eSJiong Wang #include <linux/in6.h>
10bd4aed0eSJiong Wang #include <sys/socket.h>
11bd4aed0eSJiong Wang 
123e689141SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
133e689141SToke Høiland-Jørgensen #include <bpf/bpf_endian.h>
14bd4aed0eSJiong Wang 
15bd4aed0eSJiong Wang #define SRC_REWRITE_IP6_0	0
16bd4aed0eSJiong Wang #define SRC_REWRITE_IP6_1	0
17bd4aed0eSJiong Wang #define SRC_REWRITE_IP6_2	0
18bd4aed0eSJiong Wang #define SRC_REWRITE_IP6_3	6
19bd4aed0eSJiong Wang 
20bd4aed0eSJiong Wang #define DST_REWRITE_IP6_0	0
21bd4aed0eSJiong Wang #define DST_REWRITE_IP6_1	0
22bd4aed0eSJiong Wang #define DST_REWRITE_IP6_2	0
23bd4aed0eSJiong Wang #define DST_REWRITE_IP6_3	1
24bd4aed0eSJiong Wang 
25bd4aed0eSJiong Wang #define DST_REWRITE_PORT6	6666
26bd4aed0eSJiong Wang 
27bd4aed0eSJiong Wang SEC("cgroup/connect6")
connect_v6_prog(struct bpf_sock_addr * ctx)28bd4aed0eSJiong Wang int connect_v6_prog(struct bpf_sock_addr *ctx)
29bd4aed0eSJiong Wang {
30bd4aed0eSJiong Wang 	struct bpf_sock_tuple tuple = {};
31bd4aed0eSJiong Wang 	struct sockaddr_in6 sa;
32bd4aed0eSJiong Wang 	struct bpf_sock *sk;
33bd4aed0eSJiong Wang 
34bd4aed0eSJiong Wang 	/* Verify that new destination is available. */
35bd4aed0eSJiong Wang 	memset(&tuple.ipv6.saddr, 0, sizeof(tuple.ipv6.saddr));
36bd4aed0eSJiong Wang 	memset(&tuple.ipv6.sport, 0, sizeof(tuple.ipv6.sport));
37bd4aed0eSJiong Wang 
38bd4aed0eSJiong Wang 	tuple.ipv6.daddr[0] = bpf_htonl(DST_REWRITE_IP6_0);
39bd4aed0eSJiong Wang 	tuple.ipv6.daddr[1] = bpf_htonl(DST_REWRITE_IP6_1);
40bd4aed0eSJiong Wang 	tuple.ipv6.daddr[2] = bpf_htonl(DST_REWRITE_IP6_2);
41bd4aed0eSJiong Wang 	tuple.ipv6.daddr[3] = bpf_htonl(DST_REWRITE_IP6_3);
42bd4aed0eSJiong Wang 
43bd4aed0eSJiong Wang 	tuple.ipv6.dport = bpf_htons(DST_REWRITE_PORT6);
44bd4aed0eSJiong Wang 
45bd4aed0eSJiong Wang 	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
46bd4aed0eSJiong Wang 		return 0;
47bd4aed0eSJiong Wang 	else if (ctx->type == SOCK_STREAM)
48bd4aed0eSJiong Wang 		sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6),
49bd4aed0eSJiong Wang 				       BPF_F_CURRENT_NETNS, 0);
50bd4aed0eSJiong Wang 	else
51bd4aed0eSJiong Wang 		sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6),
52bd4aed0eSJiong Wang 				       BPF_F_CURRENT_NETNS, 0);
53bd4aed0eSJiong Wang 
54bd4aed0eSJiong Wang 	if (!sk)
55bd4aed0eSJiong Wang 		return 0;
56bd4aed0eSJiong Wang 
57bd4aed0eSJiong Wang 	if (sk->src_ip6[0] != tuple.ipv6.daddr[0] ||
58bd4aed0eSJiong Wang 	    sk->src_ip6[1] != tuple.ipv6.daddr[1] ||
59bd4aed0eSJiong Wang 	    sk->src_ip6[2] != tuple.ipv6.daddr[2] ||
60bd4aed0eSJiong Wang 	    sk->src_ip6[3] != tuple.ipv6.daddr[3] ||
61bd4aed0eSJiong Wang 	    sk->src_port != DST_REWRITE_PORT6) {
62bd4aed0eSJiong Wang 		bpf_sk_release(sk);
63bd4aed0eSJiong Wang 		return 0;
64bd4aed0eSJiong Wang 	}
65bd4aed0eSJiong Wang 
66bd4aed0eSJiong Wang 	bpf_sk_release(sk);
67bd4aed0eSJiong Wang 
68bd4aed0eSJiong Wang 	/* Rewrite destination. */
69bd4aed0eSJiong Wang 	ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0);
70bd4aed0eSJiong Wang 	ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1);
71bd4aed0eSJiong Wang 	ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2);
72bd4aed0eSJiong Wang 	ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3);
73bd4aed0eSJiong Wang 
74bd4aed0eSJiong Wang 	ctx->user_port = bpf_htons(DST_REWRITE_PORT6);
75bd4aed0eSJiong Wang 
76bd4aed0eSJiong Wang 	/* Rewrite source. */
77bd4aed0eSJiong Wang 	memset(&sa, 0, sizeof(sa));
78bd4aed0eSJiong Wang 
79bd4aed0eSJiong Wang 	sa.sin6_family = AF_INET6;
80bd4aed0eSJiong Wang 	sa.sin6_port = bpf_htons(0);
81bd4aed0eSJiong Wang 
82bd4aed0eSJiong Wang 	sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0);
83bd4aed0eSJiong Wang 	sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1);
84bd4aed0eSJiong Wang 	sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2);
85bd4aed0eSJiong Wang 	sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3);
86bd4aed0eSJiong Wang 
87bd4aed0eSJiong Wang 	if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
88bd4aed0eSJiong Wang 		return 0;
89bd4aed0eSJiong Wang 
90bd4aed0eSJiong Wang 	return 1;
91bd4aed0eSJiong Wang }
92bd4aed0eSJiong Wang 
93bd4aed0eSJiong Wang char _license[] SEC("license") = "GPL";
94