/* when packets are written to the TCP stream, they are prepended with * two bytes indicating the actual packet size. * Parse accordingly and return the actual size (including the size * header)
*/
/* ensure skb->data points to the beginning of the openvpn packet */ if (!pskb_pull(skb, off)) {
net_warn_ratelimited("%s: packet too small for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id); goto err;
}
/* strparser does not trim the skb for us, therefore we do it now */ if (pskb_trim(skb, pkt_len) != 0) {
net_warn_ratelimited("%s: trimming skb failed for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id); goto err;
}
/* we need the first 4 bytes of data to be accessible * to extract the opcode and the key ID later on
*/ if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) {
net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id); goto err;
}
/* DATA_V2 packets are handled in kernel, the rest goes to user space */
opcode = ovpn_opcode_from_skb(skb, 0); if (unlikely(opcode != OVPN_DATA_V2)) { if (opcode == OVPN_DATA_V1) {
net_warn_ratelimited("%s: DATA_V1 detected on the TCP stream\n",
netdev_name(peer->ovpn->dev)); goto err;
}
/* The packet size header must be there when sending the packet * to userspace, therefore we put it back
*/
skb_push(skb, 2);
ovpn_tcp_to_userspace(peer, strp->sk, skb); return;
}
/* hold reference to peer as required by ovpn_recv(). * * NOTE: in this context we should already be holding a reference to * this peer, therefore ovpn_peer_hold() is not expected to fail
*/ if (WARN_ON(!ovpn_peer_hold(peer))) goto err_nopeer;
ovpn_recv(peer, skb); return;
err: /* take reference for deferred peer deletion. should never fail */ if (WARN_ON(!ovpn_peer_hold(peer))) goto err_nopeer;
schedule_work(&peer->tcp.defer_del_work);
dev_dstats_rx_dropped(peer->ovpn->dev);
err_nopeer:
kfree_skb(skb);
}
do {
flags = ovpn_skb_cb(skb)->nosignal ? MSG_NOSIGNAL : 0;
ret = skb_send_sock_locked_with_flags(sk, skb,
peer->tcp.out_msg.offset,
peer->tcp.out_msg.len,
flags); if (unlikely(ret < 0)) { if (ret == -EAGAIN) goto out;
net_warn_ratelimited("%s: TCP error to peer %u: %d\n",
netdev_name(peer->ovpn->dev),
peer->id, ret);
/* in case of TCP error we can't recover the VPN * stream therefore we abort the connection
*/
ovpn_peer_hold(peer);
schedule_work(&peer->tcp.defer_del_work);
/* we bail out immediately and keep tx_in_progress set * to true. This way we prevent more TX attempts * which would lead to more invocations of * schedule_work()
*/ return;
}
rcu_read_lock();
sock = rcu_dereference_sk_user_data(sk); if (!sock) {
rcu_read_unlock(); return;
}
peer = sock->peer;
/* during initialization this function is called before * assigning sock->peer
*/ if (unlikely(!peer || !ovpn_peer_hold(peer))) {
rcu_read_unlock(); return;
}
rcu_read_unlock();
/* Set TCP encapsulation callbacks */ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock, struct ovpn_peer *peer)
{ struct strp_callbacks cb = {
.rcv_msg = ovpn_tcp_rcv,
.parse_msg = ovpn_tcp_parse,
}; int ret;
/* make sure no pre-existing encapsulation handler exists */ if (ovpn_sock->sk->sk_user_data) return -EBUSY;
/* only a fully connected socket is expected. Connection should be * handled in userspace
*/ if (ovpn_sock->sk->sk_state != TCP_ESTABLISHED) {
net_err_ratelimited("%s: provided TCP socket is not in ESTABLISHED state: %d\n",
netdev_name(peer->ovpn->dev),
ovpn_sock->sk->sk_state); return -EINVAL;
}
ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb); if (ret < 0) {
DEBUG_NET_WARN_ON_ONCE(1); return ret;
}
/* save current CBs so that they can be restored upon socket release */
peer->tcp.sk_cb.sk_data_ready = ovpn_sock->sk->sk_data_ready;
peer->tcp.sk_cb.sk_write_space = ovpn_sock->sk->sk_write_space;
peer->tcp.sk_cb.prot = ovpn_sock->sk->sk_prot;
peer->tcp.sk_cb.ops = ovpn_sock->sk->sk_socket->ops;
/* assign our static CBs and prot/ops */
ovpn_sock->sk->sk_data_ready = ovpn_tcp_data_ready;
ovpn_sock->sk->sk_write_space = ovpn_tcp_write_space;
rcu_read_lock();
ovpn_sock = rcu_dereference_sk_user_data(sock->sk); /* if we landed in this callback, we expect to have a * meaningful state. The ovpn_socket lifecycle would * prevent it otherwise.
*/ if (WARN(!ovpn_sock || !ovpn_sock->peer, "ovpn: null state in ovpn_tcp_poll!")) {
rcu_read_unlock(); return 0;
}
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.