18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2018 Facebook
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <string.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/stddef.h>
78c2ecf20Sopenharmony_ci#include <linux/bpf.h>
88c2ecf20Sopenharmony_ci#include <linux/in.h>
98c2ecf20Sopenharmony_ci#include <linux/in6.h>
108c2ecf20Sopenharmony_ci#include <sys/socket.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h>
138c2ecf20Sopenharmony_ci#include <bpf/bpf_endian.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define SRC_REWRITE_IP6_0	0
168c2ecf20Sopenharmony_ci#define SRC_REWRITE_IP6_1	0
178c2ecf20Sopenharmony_ci#define SRC_REWRITE_IP6_2	0
188c2ecf20Sopenharmony_ci#define SRC_REWRITE_IP6_3	6
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define DST_REWRITE_IP6_0	0
218c2ecf20Sopenharmony_ci#define DST_REWRITE_IP6_1	0
228c2ecf20Sopenharmony_ci#define DST_REWRITE_IP6_2	0
238c2ecf20Sopenharmony_ci#define DST_REWRITE_IP6_3	1
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define DST_REWRITE_PORT6	6666
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciint _version SEC("version") = 1;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciSEC("cgroup/connect6")
308c2ecf20Sopenharmony_ciint connect_v6_prog(struct bpf_sock_addr *ctx)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct bpf_sock_tuple tuple = {};
338c2ecf20Sopenharmony_ci	struct sockaddr_in6 sa;
348c2ecf20Sopenharmony_ci	struct bpf_sock *sk;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* Verify that new destination is available. */
378c2ecf20Sopenharmony_ci	memset(&tuple.ipv6.saddr, 0, sizeof(tuple.ipv6.saddr));
388c2ecf20Sopenharmony_ci	memset(&tuple.ipv6.sport, 0, sizeof(tuple.ipv6.sport));
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	tuple.ipv6.daddr[0] = bpf_htonl(DST_REWRITE_IP6_0);
418c2ecf20Sopenharmony_ci	tuple.ipv6.daddr[1] = bpf_htonl(DST_REWRITE_IP6_1);
428c2ecf20Sopenharmony_ci	tuple.ipv6.daddr[2] = bpf_htonl(DST_REWRITE_IP6_2);
438c2ecf20Sopenharmony_ci	tuple.ipv6.daddr[3] = bpf_htonl(DST_REWRITE_IP6_3);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	tuple.ipv6.dport = bpf_htons(DST_REWRITE_PORT6);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
488c2ecf20Sopenharmony_ci		return 0;
498c2ecf20Sopenharmony_ci	else if (ctx->type == SOCK_STREAM)
508c2ecf20Sopenharmony_ci		sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6),
518c2ecf20Sopenharmony_ci				       BPF_F_CURRENT_NETNS, 0);
528c2ecf20Sopenharmony_ci	else
538c2ecf20Sopenharmony_ci		sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6),
548c2ecf20Sopenharmony_ci				       BPF_F_CURRENT_NETNS, 0);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (!sk)
578c2ecf20Sopenharmony_ci		return 0;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (sk->src_ip6[0] != tuple.ipv6.daddr[0] ||
608c2ecf20Sopenharmony_ci	    sk->src_ip6[1] != tuple.ipv6.daddr[1] ||
618c2ecf20Sopenharmony_ci	    sk->src_ip6[2] != tuple.ipv6.daddr[2] ||
628c2ecf20Sopenharmony_ci	    sk->src_ip6[3] != tuple.ipv6.daddr[3] ||
638c2ecf20Sopenharmony_ci	    sk->src_port != DST_REWRITE_PORT6) {
648c2ecf20Sopenharmony_ci		bpf_sk_release(sk);
658c2ecf20Sopenharmony_ci		return 0;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	bpf_sk_release(sk);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* Rewrite destination. */
718c2ecf20Sopenharmony_ci	ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0);
728c2ecf20Sopenharmony_ci	ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1);
738c2ecf20Sopenharmony_ci	ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2);
748c2ecf20Sopenharmony_ci	ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	ctx->user_port = bpf_htons(DST_REWRITE_PORT6);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* Rewrite source. */
798c2ecf20Sopenharmony_ci	memset(&sa, 0, sizeof(sa));
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	sa.sin6_family = AF_INET6;
828c2ecf20Sopenharmony_ci	sa.sin6_port = bpf_htons(0);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0);
858c2ecf20Sopenharmony_ci	sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1);
868c2ecf20Sopenharmony_ci	sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2);
878c2ecf20Sopenharmony_ci	sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
908c2ecf20Sopenharmony_ci		return 0;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return 1;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cichar _license[] SEC("license") = "GPL";
96