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