mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Cross-merge networking fixes after downstream PR (net-6.16-rc7). Conflicts: Documentation/netlink/specs/ovpn.yaml880d43ca9a
("netlink: specs: clean up spaces in brackets")af52020fc5
("ovpn: reject unexpected netlink attributes") drivers/net/phy/phy_device.ca44312d58e
("net: phy: Don't register LEDs for genphy")f0f2b992d8
("net: phy: Don't register LEDs for genphy") https://lore.kernel.org/20250710114926.7ec3a64f@kernel.org drivers/net/wireless/intel/iwlwifi/fw/regulatory.c drivers/net/wireless/intel/iwlwifi/mld/regulatory.c5fde0fcbd7
("wifi: iwlwifi: mask reserved bits in chan_state_active_bitmap")ea045a0de3
("wifi: iwlwifi: add support for accepting raw DSM tables by firmware") net/ipv6/mcast.cae3264a25a
("ipv6: mcast: Delay put pmc->idev in mld_del_delrec()")a8594c956c
("ipv6: mcast: Avoid a duplicate pointer check in mld_del_delrec()") https://lore.kernel.org/8cc52891-3653-4b03-a45e-05464fe495cf@kernel.org No adjacent changes. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
448 lines
12 KiB
C
448 lines
12 KiB
C
// 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/route.h>
|
|
#include <net/ipv6_stubs.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:
|
|
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, 0);
|
|
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 = ipv6_stub->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;
|
|
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), 0);
|
|
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 = {
|
|
.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();
|
|
setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock, &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 */
|
|
inet_set_bit(MC_LOOP, sk);
|
|
/* Disable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
|
|
inet_dec_convert_csum(sk);
|
|
|
|
WRITE_ONCE(udp_sk(sk)->encap_type, 0);
|
|
WRITE_ONCE(udp_sk(sk)->encap_rcv, NULL);
|
|
WRITE_ONCE(udp_sk(sk)->encap_destroy, NULL);
|
|
|
|
rcu_assign_sk_user_data(sk, NULL);
|
|
}
|