| // 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/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: | |
| ovpn_dev_dstats_rx_dropped(ovpn->dev); | |
| drop_noovpn: | |
| kfree_skb(skb); | |
| return 0; | |
| } | |
| static bool ovpn_route_key_equal(const struct ovpn_route_key *a, | |
| const struct ovpn_route_key *b) | |
| { | |
| return a->mark == b->mark && a->sport == b->sport; | |
| } | |
| /** | |
| * ovpn_dst_cache_check_key - reset peer dst cache after key changes | |
| * @peer: the peer owning the dst cache | |
| * @cache: the cache that might need to be reset | |
| * @key: the route key for the packet being transmitted | |
| * | |
| * Reset the peer dst cache if it was populated for a different route key. | |
| */ | |
| static void ovpn_dst_cache_check_key(struct ovpn_peer *peer, | |
| struct dst_cache *cache, | |
| const struct ovpn_route_key *key) | |
| { | |
| struct ovpn_route_key old_key; | |
| unsigned int seq; | |
| /* snapshot the saved key before deciding whether the cache matches */ | |
| do { | |
| seq = read_seqcount_begin(&peer->route_key_seq); | |
| old_key = peer->route_key; | |
| } while (read_seqcount_retry(&peer->route_key_seq, seq)); | |
| /* nothing changed: the current cache can be reused */ | |
| if (likely(ovpn_route_key_equal(&old_key, key))) | |
| return; | |
| /* recheck under lock because another path may have updated the key */ | |
| spin_lock_bh(&peer->lock); | |
| if (!ovpn_route_key_equal(&peer->route_key, key)) { | |
| write_seqcount_begin(&peer->route_key_seq); | |
| peer->route_key = *key; | |
| dst_cache_reset(cache); | |
| write_seqcount_end(&peer->route_key_seq); | |
| } | |
| spin_unlock_bh(&peer->lock); | |
| } | |
| /** | |
| * ovpn_dst_cache_current - check whether a route lookup matches peer state | |
| * @peer: the peer owning the bind and dst cache | |
| * @bind: the RCU bind used for the route lookup | |
| * @key: the route key used for the route lookup | |
| * | |
| * Check that @bind is still the current peer bind and that @key still matches | |
| * the peer route key. The caller must hold @peer->lock. The TX path keeps | |
| * @bind inside an RCU read-side critical section, so pointer identity is enough | |
| * to detect whether the bind was replaced while the route lookup was running. | |
| * | |
| * Return: true if the lookup result still matches the current peer state and | |
| * may update the dst cache or replace the bind. | |
| */ | |
| static bool ovpn_dst_cache_current(const struct ovpn_peer *peer, | |
| const struct ovpn_bind *bind, | |
| const struct ovpn_route_key *key) | |
| { | |
| const struct ovpn_bind *curr_bind; | |
| lockdep_assert_held(&peer->lock); | |
| curr_bind = rcu_dereference_protected(peer->bind, | |
| lockdep_is_held(&peer->lock)); | |
| return curr_bind == bind && | |
| ovpn_route_key_equal(key, &peer->route_key); | |
| } | |
| /** | |
| * 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 | |
| * @key: the route key snapshot used for cache validation and flow lookup | |
| * | |
| * 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, | |
| const struct ovpn_route_key *key) | |
| { | |
| struct sockaddr_storage remote; | |
| struct in_addr local = {}; | |
| bool reset_local = false; | |
| struct rtable *rt; | |
| struct flowi4 fl = { | |
| .saddr = bind->local.ipv4.s_addr, | |
| .daddr = bind->remote.in4.sin_addr.s_addr, | |
| .fl4_sport = key->sport, | |
| .fl4_dport = bind->remote.in4.sin_port, | |
| .flowi4_proto = sk->sk_protocol, | |
| .flowi4_mark = key->mark, | |
| }; | |
| int ret; | |
| local_bh_disable(); | |
| rt = dst_cache_get_ip4(cache, &fl.saddr); | |
| if (rt) | |
| goto transmit; | |
| if (fl.saddr && unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0, | |
| fl.saddr, RT_SCOPE_HOST))) { | |
| /* The learned local address is not usable anymore. | |
| * Retry with source address autoselection. | |
| */ | |
| fl.saddr = 0; | |
| reset_local = true; | |
| } | |
| rt = ip_route_output_flow(sock_net(sk), &fl, sk); | |
| if (IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) { | |
| fl.saddr = 0; | |
| reset_local = true; | |
| 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; | |
| } | |
| /* avoid storing a stale cache or local address */ | |
| spin_lock_bh(&peer->lock); | |
| if (likely(ovpn_dst_cache_current(peer, bind, key))) { | |
| if (!reset_local) { | |
| dst_cache_set_ip4(cache, &rt->dst, fl.saddr); | |
| spin_unlock_bh(&peer->lock); | |
| goto transmit; | |
| } | |
| /* invalidate per-CPU dst entries that may still carry | |
| * the stale source | |
| */ | |
| dst_cache_reset(cache); | |
| /* preserve the current remote */ | |
| memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in)); | |
| /* The current packet already has a valid wildcard-source route. | |
| * If replacing the bind fails, leave the stale local in place; | |
| * a later cache miss will retry the repair. | |
| */ | |
| ovpn_peer_reset_sockaddr(peer, &remote, &local); | |
| } | |
| spin_unlock_bh(&peer->lock); | |
| 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 | |
| * @key: the route key snapshot used for cache validation and flow lookup | |
| * | |
| * 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, | |
| const struct ovpn_route_key *key) | |
| { | |
| struct in6_addr local = in6addr_any; | |
| struct sockaddr_storage remote; | |
| bool reset_local = false; | |
| struct dst_entry *dst; | |
| int ret; | |
| struct flowi6 fl = { | |
| .saddr = bind->local.ipv6, | |
| .daddr = bind->remote.in6.sin6_addr, | |
| .fl6_sport = key->sport, | |
| .fl6_dport = bind->remote.in6.sin6_port, | |
| .flowi6_proto = sk->sk_protocol, | |
| .flowi6_mark = key->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 (!ipv6_addr_any(&fl.saddr) && | |
| unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) { | |
| /* The learned local address is not usable anymore. | |
| * Retry with source address autoselection. | |
| */ | |
| fl.saddr = in6addr_any; | |
| reset_local = true; | |
| } | |
| dst = ip6_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; | |
| } | |
| /* avoid storing a stale cache or local address */ | |
| spin_lock_bh(&peer->lock); | |
| if (likely(ovpn_dst_cache_current(peer, bind, key))) { | |
| if (!reset_local) { | |
| dst_cache_set_ip6(cache, dst, &fl.saddr); | |
| spin_unlock_bh(&peer->lock); | |
| goto transmit; | |
| } | |
| /* invalidate per-CPU dst entries that may still carry | |
| * the stale source | |
| */ | |
| dst_cache_reset(cache); | |
| /* preserve the current remote */ | |
| memcpy(&remote, &bind->remote, sizeof(struct sockaddr_in6)); | |
| /* The current packet already has a valid wildcard-source route. | |
| * If replacing the bind fails, leave the stale local in place; | |
| * a later cache miss will retry the repair. | |
| */ | |
| ovpn_peer_reset_sockaddr(peer, &remote, &local); | |
| } | |
| spin_unlock_bh(&peer->lock); | |
| 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 | |
| * @key: route key snapshot used for cache validation and flow lookup | |
| * | |
| * 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_route_key *key) | |
| { | |
| 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, key); | |
| break; | |
| #if IS_ENABLED(CONFIG_IPV6) | |
| case AF_INET6: | |
| ret = ovpn_udp6_output(peer, bind, cache, sk, skb, key); | |
| 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) | |
| { | |
| struct ovpn_route_key key = { | |
| .mark = READ_ONCE(sk->sk_mark), | |
| .sport = READ_ONCE(inet_sk(sk)->inet_sport), | |
| }; | |
| int ret; | |
| skb->dev = peer->ovpn->dev; | |
| skb->mark = key.mark; | |
| /* no checksum performed at this layer */ | |
| skb->ip_summed = CHECKSUM_NONE; | |
| ovpn_dst_cache_check_key(peer, &peer->dst_cache, &key); | |
| /* crypto layer -> transport (UDP) */ | |
| ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb, &key); | |
| 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(); | |
| 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 */ | |
| 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); | |
| } |