[PATCH ovpn net v2 3/5] ovpn: reject multipeer peers without VPN addresses
Ralf Lici <[email protected]>
| Newsgroups | gmane.network.openvpn.devel |
|---|---|
| Message-ID | <21af0a98270dc43e5720734834bdd836b8384b52.1787919082.git.ralf@mandelbit.com> |
In MP mode, ovpn uses the peer VPN addresses to select the peer for
outgoing tunnel packets. Peer creation currently requires a VPN IPv4 or
IPv6 attribute, but it only checks for the presence of the attribute and
not for a usable address value.
This allows userspace to create an MP peer with only unspecified VPN
addresses, or to update an existing peer so that both VPN address
families become unspecified. Such a peer cannot be selected through the
VPN address hash tables.
Reject MP peer creation or update when the resulting peer would not have
at least one VPN address configured.
This changes such configurations from being accepted to being rejected,
but they have never been usable because the peer cannot be selected
through the VPN address hash tables.
Fixes: 1d36a36f6d53 ("ovpn: implement peer add/get/dump/delete via netlink")
Signed-off-by: Ralf Lici <[email protected]>
---
Changes since v1 https://lore.kernel.org/openvpn-devel/17ced9a7caee691e602e3c02f5e399aa9a35067c.1785338921.git.ralf@mandelbit.com/
- Explicitly stated that the policy introduced by this commit is not
breaking userspace. (Sabrina)
- Used htonl(INADDR_ANY) instead of directly comparing s_addr. (Sabrina)
drivers/net/ovpn/netlink.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index a444930234b6..a0ed09278a6b 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -346,8 +346,10 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
{
- struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
+ struct in_addr vpn_addr4 = { .s_addr = htonl(INADDR_ANY) };
+ struct in6_addr vpn_addr6 = IN6ADDR_ANY_INIT;
struct ovpn_priv *ovpn = info->user_ptr[0];
+ struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
struct ovpn_socket *ovpn_sock;
struct socket *sock = NULL;
struct ovpn_peer *peer;
@@ -371,11 +373,20 @@ int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* in MP mode VPN IPs are required for selecting the right peer */
- if (ovpn->mode == OVPN_MODE_MP && !attrs[OVPN_A_PEER_VPN_IPV4] &&
- !attrs[OVPN_A_PEER_VPN_IPV6]) {
- NL_SET_ERR_MSG_FMT_MOD(info->extack,
- "VPN IP must be provided in MP mode");
- return -EINVAL;
+ if (ovpn->mode == OVPN_MODE_MP) {
+ if (attrs[OVPN_A_PEER_VPN_IPV4])
+ vpn_addr4.s_addr =
+ nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
+ if (attrs[OVPN_A_PEER_VPN_IPV6])
+ vpn_addr6 =
+ nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
+
+ if (vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+ ipv6_addr_any(&vpn_addr6)) {
+ NL_SET_ERR_MSG_FMT_MOD(info->extack,
+ "at least one VPN IP must be configured in MP mode");
+ return -EINVAL;
+ }
}
peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
@@ -525,6 +536,9 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
spin_lock_bh(&ovpn->lock);
+ vpn_addr4 = peer->vpn_addrs.ipv4;
+ vpn_addr6 = peer->vpn_addrs.ipv6;
+
/* reject peer with conflicting VPN address */
if (attrs[OVPN_A_PEER_VPN_IPV4]) {
vpn_addr4.s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
@@ -537,6 +551,16 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
goto addr_conflict;
}
+ /* in MP mode VPN IPs are required for selecting the right peer */
+ if (ovpn->mode == OVPN_MODE_MP &&
+ vpn_addr4.s_addr == htonl(INADDR_ANY) &&
+ ipv6_addr_any(&vpn_addr6)) {
+ NL_SET_ERR_MSG_FMT_MOD(info->extack,
+ "at least one VPN IP must be configured in MP mode");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
ret = ovpn_nl_peer_modify(peer, info, attrs);
if (ret < 0)
goto unlock;
--
2.55.0