1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <string.h> |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <linux/in.h> |
6 | #include <linux/in6.h> |
7 | #include <sys/socket.h> |
8 | |
9 | #include <bpf/bpf_helpers.h> |
10 | #include <bpf/bpf_endian.h> |
11 | |
12 | #include <bpf_sockopt_helpers.h> |
13 | |
14 | char _license[] SEC("license" ) = "GPL" ; |
15 | |
16 | struct svc_addr { |
17 | __be32 addr[4]; |
18 | __be16 port; |
19 | }; |
20 | |
21 | struct { |
22 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
23 | __uint(map_flags, BPF_F_NO_PREALLOC); |
24 | __type(key, int); |
25 | __type(value, struct svc_addr); |
26 | } service_mapping SEC(".maps" ); |
27 | |
28 | SEC("cgroup/connect6" ) |
29 | int connect6(struct bpf_sock_addr *ctx) |
30 | { |
31 | struct sockaddr_in6 sa = {}; |
32 | struct svc_addr *orig; |
33 | |
34 | /* Force local address to [::1]:22223. */ |
35 | sa.sin6_family = AF_INET6; |
36 | sa.sin6_port = bpf_htons(22223); |
37 | sa.sin6_addr.s6_addr32[3] = bpf_htonl(1); |
38 | |
39 | if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) |
40 | return 0; |
41 | |
42 | /* Rewire service [fc00::1]:60000 to backend [::1]:60124. */ |
43 | if (ctx->user_port == bpf_htons(60000)) { |
44 | orig = bpf_sk_storage_get(&service_mapping, ctx->sk, 0, |
45 | BPF_SK_STORAGE_GET_F_CREATE); |
46 | if (!orig) |
47 | return 0; |
48 | |
49 | orig->addr[0] = ctx->user_ip6[0]; |
50 | orig->addr[1] = ctx->user_ip6[1]; |
51 | orig->addr[2] = ctx->user_ip6[2]; |
52 | orig->addr[3] = ctx->user_ip6[3]; |
53 | orig->port = ctx->user_port; |
54 | |
55 | ctx->user_ip6[0] = 0; |
56 | ctx->user_ip6[1] = 0; |
57 | ctx->user_ip6[2] = 0; |
58 | ctx->user_ip6[3] = bpf_htonl(1); |
59 | ctx->user_port = bpf_htons(60124); |
60 | } |
61 | return 1; |
62 | } |
63 | |
64 | SEC("cgroup/getsockname6" ) |
65 | int getsockname6(struct bpf_sock_addr *ctx) |
66 | { |
67 | if (!get_set_sk_priority(ctx)) |
68 | return 1; |
69 | |
70 | /* Expose local server as [fc00::1]:60000 to client. */ |
71 | if (ctx->user_port == bpf_htons(60124)) { |
72 | ctx->user_ip6[0] = bpf_htonl(0xfc000000); |
73 | ctx->user_ip6[1] = 0; |
74 | ctx->user_ip6[2] = 0; |
75 | ctx->user_ip6[3] = bpf_htonl(1); |
76 | ctx->user_port = bpf_htons(60000); |
77 | } |
78 | return 1; |
79 | } |
80 | |
81 | SEC("cgroup/getpeername6" ) |
82 | int getpeername6(struct bpf_sock_addr *ctx) |
83 | { |
84 | struct svc_addr *orig; |
85 | |
86 | if (!get_set_sk_priority(ctx)) |
87 | return 1; |
88 | |
89 | /* Expose service [fc00::1]:60000 as peer instead of backend. */ |
90 | if (ctx->user_port == bpf_htons(60124)) { |
91 | orig = bpf_sk_storage_get(&service_mapping, ctx->sk, 0, 0); |
92 | if (orig) { |
93 | ctx->user_ip6[0] = orig->addr[0]; |
94 | ctx->user_ip6[1] = orig->addr[1]; |
95 | ctx->user_ip6[2] = orig->addr[2]; |
96 | ctx->user_ip6[3] = orig->addr[3]; |
97 | ctx->user_port = orig->port; |
98 | } |
99 | } |
100 | return 1; |
101 | } |
102 | |