/* Retrieve the corresponding ovpn object from a UDP socket * rcu_read_lock must be held on entry
*/ staticstruct 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)
*/ staticint 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;
/** * 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
*/ staticint 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);
}
#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
*/ staticint 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;
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
*/ staticint 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);
}
/** * 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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.