162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2018 Facebook
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <string.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/stddef.h>
762306a36Sopenharmony_ci#include <linux/bpf.h>
862306a36Sopenharmony_ci#include <linux/in.h>
962306a36Sopenharmony_ci#include <linux/in6.h>
1062306a36Sopenharmony_ci#include <sys/socket.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
1362306a36Sopenharmony_ci#include <bpf/bpf_endian.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define SRC_REWRITE_IP6_0	0
1662306a36Sopenharmony_ci#define SRC_REWRITE_IP6_1	0
1762306a36Sopenharmony_ci#define SRC_REWRITE_IP6_2	0
1862306a36Sopenharmony_ci#define SRC_REWRITE_IP6_3	6
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define DST_REWRITE_IP6_0	0
2162306a36Sopenharmony_ci#define DST_REWRITE_IP6_1	0
2262306a36Sopenharmony_ci#define DST_REWRITE_IP6_2	0
2362306a36Sopenharmony_ci#define DST_REWRITE_IP6_3	1
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DST_REWRITE_PORT6	6666
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciSEC("cgroup/connect6")
2862306a36Sopenharmony_ciint connect_v6_prog(struct bpf_sock_addr *ctx)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct bpf_sock_tuple tuple = {};
3162306a36Sopenharmony_ci	struct sockaddr_in6 sa;
3262306a36Sopenharmony_ci	struct bpf_sock *sk;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* Verify that new destination is available. */
3562306a36Sopenharmony_ci	memset(&tuple.ipv6.saddr, 0, sizeof(tuple.ipv6.saddr));
3662306a36Sopenharmony_ci	memset(&tuple.ipv6.sport, 0, sizeof(tuple.ipv6.sport));
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	tuple.ipv6.daddr[0] = bpf_htonl(DST_REWRITE_IP6_0);
3962306a36Sopenharmony_ci	tuple.ipv6.daddr[1] = bpf_htonl(DST_REWRITE_IP6_1);
4062306a36Sopenharmony_ci	tuple.ipv6.daddr[2] = bpf_htonl(DST_REWRITE_IP6_2);
4162306a36Sopenharmony_ci	tuple.ipv6.daddr[3] = bpf_htonl(DST_REWRITE_IP6_3);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	tuple.ipv6.dport = bpf_htons(DST_REWRITE_PORT6);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
4662306a36Sopenharmony_ci		return 0;
4762306a36Sopenharmony_ci	else if (ctx->type == SOCK_STREAM)
4862306a36Sopenharmony_ci		sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6),
4962306a36Sopenharmony_ci				       BPF_F_CURRENT_NETNS, 0);
5062306a36Sopenharmony_ci	else
5162306a36Sopenharmony_ci		sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6),
5262306a36Sopenharmony_ci				       BPF_F_CURRENT_NETNS, 0);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (!sk)
5562306a36Sopenharmony_ci		return 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (sk->src_ip6[0] != tuple.ipv6.daddr[0] ||
5862306a36Sopenharmony_ci	    sk->src_ip6[1] != tuple.ipv6.daddr[1] ||
5962306a36Sopenharmony_ci	    sk->src_ip6[2] != tuple.ipv6.daddr[2] ||
6062306a36Sopenharmony_ci	    sk->src_ip6[3] != tuple.ipv6.daddr[3] ||
6162306a36Sopenharmony_ci	    sk->src_port != DST_REWRITE_PORT6) {
6262306a36Sopenharmony_ci		bpf_sk_release(sk);
6362306a36Sopenharmony_ci		return 0;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	bpf_sk_release(sk);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Rewrite destination. */
6962306a36Sopenharmony_ci	ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0);
7062306a36Sopenharmony_ci	ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1);
7162306a36Sopenharmony_ci	ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2);
7262306a36Sopenharmony_ci	ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ctx->user_port = bpf_htons(DST_REWRITE_PORT6);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Rewrite source. */
7762306a36Sopenharmony_ci	memset(&sa, 0, sizeof(sa));
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	sa.sin6_family = AF_INET6;
8062306a36Sopenharmony_ci	sa.sin6_port = bpf_htons(0);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0);
8362306a36Sopenharmony_ci	sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1);
8462306a36Sopenharmony_ci	sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2);
8562306a36Sopenharmony_ci	sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
8862306a36Sopenharmony_ci		return 0;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 1;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
94