Commit a215d253 authored by Antonio Quartulli's avatar Antonio Quartulli Committed by Paolo Abeni
Browse files

ovpn: notify userspace when a peer is deleted



Whenever a peer is deleted, send a notification to userspace so that it
can react accordingly.

This is most important when a peer is deleted due to ping timeout,
because it all happens in kernelspace and thus userspace has no direct
way to learn about it.

Signed-off-by: default avatarAntonio Quartulli <antonio@openvpn.net>
Link: https://patch.msgid.link/20250415-b4-ovpn-v26-21-577f6097b964@openvpn.net


Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Tested-by: default avatarOleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 89d3c0e4
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -1103,6 +1103,71 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info)
	return 0;
}

/**
 * ovpn_nl_peer_del_notify - notify userspace about peer being deleted
 * @peer: the peer being deleted
 *
 * Return: 0 on success or a negative error code otherwise
 */
int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
{
	struct ovpn_socket *sock;
	struct sk_buff *msg;
	struct nlattr *attr;
	int ret = -EMSGSIZE;
	void *hdr;

	netdev_info(peer->ovpn->dev, "deleting peer with id %u, reason %d\n",
		    peer->id, peer->delete_reason);

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
	if (!msg)
		return -ENOMEM;

	hdr = genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, OVPN_CMD_PEER_DEL_NTF);
	if (!hdr) {
		ret = -ENOBUFS;
		goto err_free_msg;
	}

	if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex))
		goto err_cancel_msg;

	attr = nla_nest_start(msg, OVPN_A_PEER);
	if (!attr)
		goto err_cancel_msg;

	if (nla_put_u32(msg, OVPN_A_PEER_DEL_REASON, peer->delete_reason))
		goto err_cancel_msg;

	if (nla_put_u32(msg, OVPN_A_PEER_ID, peer->id))
		goto err_cancel_msg;

	nla_nest_end(msg, attr);

	genlmsg_end(msg, hdr);

	rcu_read_lock();
	sock = rcu_dereference(peer->sock);
	if (!sock) {
		ret = -EINVAL;
		goto err_unlock;
	}
	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
				msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
	rcu_read_unlock();

	return 0;

err_unlock:
	rcu_read_unlock();
err_cancel_msg:
	genlmsg_cancel(msg, hdr);
err_free_msg:
	nlmsg_free(msg);
	return ret;
}

/**
 * ovpn_nl_key_swap_notify - notify userspace peer's key must be renewed
 * @peer: the peer whose key needs to be renewed
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
int ovpn_nl_register(void);
void ovpn_nl_unregister(void);

int ovpn_nl_peer_del_notify(struct ovpn_peer *peer);
int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id);

#endif /* _NET_OVPN_NETLINK_H_ */
+1 −0
Original line number Diff line number Diff line
@@ -706,6 +706,7 @@ static void ovpn_peer_remove(struct ovpn_peer *peer,
	}

	peer->delete_reason = reason;
	ovpn_nl_peer_del_notify(peer);

	/* append to provided list for later socket release and ref drop */
	llist_add(&peer->release_entry, release_list);