On Fri, 14 Aug 2026 11:52:20 +0200, Sabrina Dubroca <[email protected]> 
wrote:
> 2026-07-29, 17:37:40 +0200, Ralf Lici wrote:
> > In MP mode, ovpn uses the peer VPN addresses as lookup keys for
> > selecting the peer that should receive an outgoing tunnel packet.
> > However, the netlink peer configuration path does not currently reject
> > duplicate VPN addresses.
> > 
> > If two peers are configured with the same VPN address, both can be
> > inserted in the VPN address hash table and lookups return whichever peer
> > is found first. This makes peer selection ambiguous and dependent on
> > hash insertion order.
> > 
> > Reject peer creation or update when the resulting VPN address is already
> > assigned to another peer. Ignore unspecified addresses because those are
> > not inserted in the VPN address hash tables.
>
> Maybe mention that it's a user-visible change of behavior, but it
> doesn't matter since that setup has never worked.
>
>

Will do.

> > @@ -522,22 +524,41 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct 
> > genl_info *info)
> >     rcu_read_unlock();
> >  
> >     spin_lock_bh(&ovpn->lock);
> > -   ret = ovpn_nl_peer_modify(peer, info, attrs);
> > -   if (ret < 0) {
> > -           spin_unlock_bh(&ovpn->lock);
> > -           ovpn_peer_put(peer);
> > -           return ret;
> > +
> > +   vpn_addr4 = peer->vpn_addrs.ipv4;
> > +   vpn_addr6 = peer->vpn_addrs.ipv6;
> > +
> > +   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]);
> > +
> > +   /* reject peer with conflicting VPN address */
> > +   if ((attrs[OVPN_A_PEER_VPN_IPV4] || attrs[OVPN_A_PEER_VPN_IPV6]) &&
> > +       ovpn_peer_vpn_addr_conflict(ovpn, peer, &vpn_addr4, &vpn_addr6)) {
> > +           NL_SET_ERR_MSG_FMT_MOD(info->extack,
> > +                                  "VPN IP is already assigned to another 
> > peer");
> > +           ret = -EADDRINUSE;
> > +           goto unlock;
> >     }
>
> nit: maybe splitting conflict() into conflict{4,6}() would be a bit
> cleaner? passing addresses of 2 families feels kind of strange.
>
>       if (attrs[OVPN_A_PEER_VPN_IPV4]) {
>               struct in_addr vpn_addr4 = {
>                       .s_addr = nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]),
>               };
>               if (ovpn_peer_vpn_addr_conflict4(ovpn, peer, &vpn_addr4))
>                       goto addr_conflict;
>       }
>
>
> And then conflict* looks slightly nicer too:
>
> bool ovpn_peer_vpn_addr_conflict4(struct ovpn_priv *ovpn,
>                                 const struct ovpn_peer *peer,
>                                 const struct in_addr *addr)
> {
>       struct ovpn_peer *tmp = NULL;
>
>       lockdep_assert_held(&ovpn->lock);
>
>       /* we don't hash INADDR_ANY, no conflict in that case */
>       if (addr->s_addr != htonl(INADDR_ANY))
>               tmp = ovpn_peer_get_by_vpn_addr4(ovpn, addr->s_addr);
>
>       return tmp && tmp != peer;
> }
>

Yes, it's a nice refactoring. I'll apply it to v2.

-- 
Ralf Lici
Mandelbit Srl


_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to