// SPDX-License-Identifier: GPL-2.0
/*  OpenVPN data channel offload
 *
 *  Copyright (C) 2019-2025 OpenVPN, Inc.
 *
 *  Author:	Antonio Quartulli <antonio@openvpn.net>
 */

#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/udp.h>
#include <net/addrconf.h>
#include <net/dst_cache.h>
#include <net/ip6_route.h>
#include <net/route.h>
#include <net/transp_v6.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>

#include "ovpnpriv.h"
#include "main.h"
#include "bind.h"
#include "io.h"
#include "peer.h"
#include "proto.h"
#include "socket.h"
#include "udp.h"

/* Retrieve the corresponding ovpn object from a UDP socket
 * rcu_read_lock must be held on entry
 */
static struct ovpn_socket *ovpn_socket_from_udp_sock(struct sock *sk)
{
	struct ovpn_socket *ovpn_sock;

	if (unlikely(READ_ONCE(udp_sk(sk)->encap_type) != UDP_ENCAP_OVPNINUDP))
		return NULL;

	ovpn_sock = rcu_dereference_sk_user_data(sk);
	if (unlikely(!ovpn_sock))
		return NULL;

	/* make sure that sk matches our stored transport socket */
	if (unlikely(!ovpn_sock->sk || sk != ovpn_sock->sk))
		return NULL;

	return ovpn_sock;
}

/**
 * ovpn_udp_encap_recv - Start processing a received UDP packet.
 * @sk: socket over which the packet was received
 * @skb: the received packet
 *
 * If the first byte of the payload is:
 * - DATA_V2 the packet is accepted for further processing,
 * - DATA_V1 the packet is dropped as not supported,
 * - anything else the packet is forwarded to the UDP stack for
 *   delivery to user space.
 *
 * Return:
 *  0 if skb was consumed or dropped
 * >0 if skb should be passed up to userspace as UDP (packet not consumed)
 * <0 if skb should be resubmitted as proto -N (packet not consumed)
 */
static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
	struct ovpn_socket *ovpn_sock;
	struct ovpn_priv *ovpn;
	struct ovpn_peer *peer;
	u32 peer_id;
	u8 opcode;

	ovpn_sock = ovpn_socket_from_udp_sock(sk);
	if (unlikely(!ovpn_sock)) {
		net_err_ratelimited("ovpn: %s invoked on non ovpn socket\n",
				    __func__);
		goto drop_noovpn;
	}

	ovpn = ovpn_sock->ovpn;
	if (unlikely(!ovpn)) {
		net_err_ratelimited("ovpn: cannot obtain ovpn object from UDP socket\n");
		goto drop_noovpn;
	}

	/* Make sure the first 4 bytes of the skb data buffer after the UDP
	 * header are accessible.
	 * They are required to fetch the OP code, the key ID and the peer ID.
	 */
	if (unlikely(!pskb_may_pull(skb, sizeof(struct udphdr) +
				    OVPN_OPCODE_SIZE))) {
		net_dbg_ratelimited("%s: packet too small from UDP socket\n",
				    netdev_name(ovpn->dev));
		goto drop;
	}

	opcode = ovpn_opcode_from_skb(skb, sizeof(struct udphdr));
	if (unlikely(opcode != OVPN_DATA_V2)) {
		/* DATA_V1 is not supported */
		if (opcode == OVPN_DATA_V1)
			goto drop;

		/* unknown or control packet: let it bubble up to userspace */
		return 1;
	}

	peer_id = ovpn_peer_id_from_skb(skb, sizeof(struct udphdr));
	/* some OpenVPN server implementations send data packets with the
	 * peer-id set to UNDEF. In this case we skip the peer lookup by peer-id
	 * and we try with the transport address
	 */
	if (peer_id == OVPN_PEER_ID_UNDEF)
		peer = ovpn_peer_get_by_transp_addr(ovpn, skb);
	else
		peer = ovpn_peer_get_by_id(ovpn, peer_id);

	if (unlikely(!peer))
		goto drop;

	/* pop off outer UDP header */
	__skb_pull(skb, sizeof(struct udphdr));
	ovpn_recv(peer, skb);
	return 0;

drop:
	dev_dstats_rx_dropped(ovpn->dev);
drop_noovpn:
	kfree_skb(skb);
	return 0;
}

/**
 * ovpn_udp4_output - send IPv4 packet over udp socket
 * @peer: the destination peer
 * @bind: the binding related to the destination peer
 * @cache: dst cache
 * @sk: the socket to send the packet over
 * @skb: the packet to send
 *
 * Return: 0 on success or a negative error code otherwise
 */
static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
			    struct dst_cache *cache, struct sock *sk,
			    struct sk_buff *skb)
{
	struct rtable *rt;
	struct flowi4 fl = {
		.saddr = bind->local.ipv4.s_addr,
		.daddr = bind->remote.in4.sin_addr.s_addr,
		.fl4_sport = inet_sk(sk)->inet_sport,
		.fl4_dport = bind->remote.in4.sin_port,
		.flowi4_proto = sk->sk_protocol,
		.flowi4_mark = sk->sk_mark,
	};
	int ret;

	local_bh_disable();
	rt = dst_cache_get_ip4(cache, &fl.saddr);
	if (rt)
		goto transmit;

	if (unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0, fl.saddr,
					RT_SCOPE_HOST))) {
		/* we may end up here when the cached address is not usable
		 * anymore. In this case we reset address/cache and perform a
		 * new look up
		 */
		fl.saddr = 0;
		spin_lock_bh(&peer->lock);
		bind->local.ipv4.s_addr = 0;
		spin_unlock_bh(&peer->lock);
		dst_cache_reset(cache);
	}

	rt = ip_route_output_flow(sock_net(sk), &fl, sk);
	if (IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) {
		fl.saddr = 0;
		spin_lock_bh(&peer->lock);
		bind->local.ipv4.s_addr = 0;
		spin_unlock_bh(&peer->lock);
		dst_cache_reset(cache);

		rt = ip_route_output_flow(sock_net(sk), &fl, sk);
	}

	if (IS_ERR(rt)) {
		ret = PTR_ERR(rt);
		net_dbg_ratelimited("%s: no route to host %pISpc: %d\n",
				    netdev_name(peer->ovpn->dev),
				    &bind->remote.in4,
				    ret);
		goto err;
	}
	dst_cache_set_ip4(cache, &rt->dst, fl.saddr);

transmit:
	ovpn_udp_tunnel_xmit_skb(rt, sk, skb, fl.saddr, fl.daddr, 0,
				 ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
				 fl.fl4_dport, false, sk->sk_no_check_tx);
	ret = 0;
err:
	local_bh_enable();
	return ret;
}

#if IS_ENABLED(CONFIG_IPV6)
/**
 * ovpn_udp6_output - send IPv6 packet over udp socket
 * @peer: the destination peer
 * @bind: the binding related to the destination peer
 * @cache: dst cache
 * @sk: the socket to send the packet over
 * @skb: the packet to send
 *
 * Return: 0 on success or a negative error code otherwise
 */
static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
			    struct dst_cache *cache, struct sock *sk,
			    struct sk_buff *skb)
{
	struct dst_entry *dst;
	int ret;

	struct flowi6 fl = {
		.saddr = bind->local.ipv6,
		.daddr = bind->remote.in6.sin6_addr,
		.fl6_sport = inet_sk(sk)->inet_sport,
		.fl6_dport = bind->remote.in6.sin6_port,
		.flowi6_proto = sk->sk_protocol,
		.flowi6_mark = sk->sk_mark,
		.flowi6_oif = bind->remote.in6.sin6_scope_id,
	};

	local_bh_disable();
	dst = dst_cache_get_ip6(cache, &fl.saddr);
	if (dst)
		goto transmit;

	if (unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) {
		/* we may end up here when the cached address is not usable
		 * anymore. In this case we reset address/cache and perform a
		 * new look up
		 */
		fl.saddr = in6addr_any;
		spin_lock_bh(&peer->lock);
		bind->local.ipv6 = in6addr_any;
		spin_unlock_bh(&peer->lock);
		dst_cache_reset(cache);
	}

	dst = ovpn_ipv6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
	if (IS_ERR(dst)) {
		ret = PTR_ERR(dst);
		net_dbg_ratelimited("%s: no route to host %pISpc: %d\n",
				    netdev_name(peer->ovpn->dev),
				    &bind->remote.in6, ret);
		goto err;
	}
	dst_cache_set_ip6(cache, dst, &fl.saddr);

transmit:
	/* user IPv6 packets may be larger than the transport interface
	 * MTU (after encapsulation), however, since they are locally
	 * generated we should ensure they get fragmented.
	 * Setting the ignore_df flag to 1 will instruct ip6_fragment() to
	 * fragment packets if needed.
	 *
	 * NOTE: this is not needed for IPv4 because we pass df=0 to
	 * udp_tunnel_xmit_skb()
	 */
	skb->ignore_df = 1;
	ovpn_udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr,
				  0, ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
				  fl.fl6_dport, udp_get_no_check6_tx(sk));
	ret = 0;
err:
	local_bh_enable();
	return ret;
}
#endif

/**
 * ovpn_udp_output - transmit skb using udp-tunnel
 * @peer: the destination peer
 * @cache: dst cache
 * @sk: the socket to send the packet over
 * @skb: the packet to send
 *
 * rcu_read_lock should be held on entry.
 * On return, the skb is consumed.
 *
 * Return: 0 on success or a negative error code otherwise
 */
static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache,
			   struct sock *sk, struct sk_buff *skb)
{
	struct ovpn_bind *bind;
	int ret;

	/* set sk to null if skb is already orphaned */
	if (!skb->destructor)
		skb->sk = NULL;

	rcu_read_lock();
	bind = rcu_dereference(peer->bind);
	if (unlikely(!bind)) {
		net_warn_ratelimited("%s: no bind for remote peer %u\n",
				     netdev_name(peer->ovpn->dev), peer->id);
		ret = -ENODEV;
		goto out;
	}

	switch (bind->remote.in4.sin_family) {
	case AF_INET:
		ret = ovpn_udp4_output(peer, bind, cache, sk, skb);
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case AF_INET6:
		ret = ovpn_udp6_output(peer, bind, cache, sk, skb);
		break;
#endif
	default:
		ret = -EAFNOSUPPORT;
		break;
	}

out:
	rcu_read_unlock();
	return ret;
}

/**
 * ovpn_udp_send_skb - prepare skb and send it over via UDP
 * @peer: the destination peer
 * @sk: peer socket
 * @skb: the packet to send
 */
void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk,
		       struct sk_buff *skb)
{
	int ret;

	skb->dev = peer->ovpn->dev;
	skb->mark = READ_ONCE(sk->sk_mark);
	/* no checksum performed at this layer */
	skb->ip_summed = CHECKSUM_NONE;

	/* crypto layer -> transport (UDP) */
	ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb);
	if (unlikely(ret < 0))
		kfree_skb(skb);
}

static void ovpn_udp_encap_destroy(struct sock *sk)
{
	struct ovpn_socket *sock;
	struct ovpn_priv *ovpn;

	rcu_read_lock();
	sock = rcu_dereference_sk_user_data(sk);
	if (!sock || !sock->ovpn) {
		rcu_read_unlock();
		return;
	}
	ovpn = sock->ovpn;
	rcu_read_unlock();

	ovpn_peers_free(ovpn, sk, OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT);
}

/**
 * ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn
 * @ovpn_sock: socket to configure
 * @sock: the socket container to be passed to setup_udp_tunnel_sock()
 * @ovpn: the openvp instance to link
 *
 * After invoking this function, the sock will be controlled by ovpn so that
 * any incoming packet may be processed by ovpn first.
 *
 * Return: 0 on success or a negative error code otherwise
 */
int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
			   struct ovpn_priv *ovpn)
{
	struct udp_tunnel_sock_cfg cfg = {
		.sk_user_data = ovpn_sock,
		.encap_type = UDP_ENCAP_OVPNINUDP,
		.encap_rcv = ovpn_udp_encap_recv,
		.encap_destroy = ovpn_udp_encap_destroy,
	};
	struct ovpn_socket *old_data;
	int ret;

	/* make sure no pre-existing encapsulation handler exists */
	rcu_read_lock();
	old_data = rcu_dereference_sk_user_data(ovpn_sock->sk);
	if (!old_data) {
		/* socket is currently unused - we can take it */
		rcu_read_unlock();
		ovpn_setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock->sk,
					   &cfg);
		return 0;
	}

	/* socket is in use. We need to understand if it's owned by this ovpn
	 * instance or by something else.
	 * In the former case, we can increase the refcounter and happily
	 * use it, because the same UDP socket is expected to be shared among
	 * different peers.
	 *
	 * Unlikely TCP, a single UDP socket can be used to talk to many remote
	 * hosts and therefore openvpn instantiates one only for all its peers
	 */
	if ((READ_ONCE(udp_sk(ovpn_sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) &&
	    old_data->ovpn == ovpn) {
		netdev_dbg(ovpn->dev,
			   "provided socket already owned by this interface\n");
		ret = -EALREADY;
	} else {
		netdev_dbg(ovpn->dev,
			   "provided socket already taken by other user\n");
		ret = -EBUSY;
	}
	rcu_read_unlock();

	return ret;
}

/**
 * ovpn_udp_socket_detach - clean udp-tunnel status for this socket
 * @ovpn_sock: the socket to clean
 */
void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock)
{
	struct sock *sk = ovpn_sock->sk;

	/* Re-enable multicast loopback */
	ovpn_udp_set_mc_loop(sk);
	/* Disable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
	inet_dec_convert_csum(sk);

	WRITE_ONCE(udp_sk(sk)->encap_type, 0);
	ovpn_udp_clear_encap_err_rcv(sk);
	WRITE_ONCE(udp_sk(sk)->encap_destroy, NULL);

	rcu_assign_sk_user_data(sk, NULL);
}
