Send a netlink notification when a client updates its remote UDP
endpoint. The notification includes the new IP address, port, and scope
ID (for IPv6).

Signed-off-by: Ralf Lici <[email protected]>
Signed-off-by: Antonio Quartulli <[email protected]>
---
Changes since v1:
- correctly set return value for unsupported AF in
  ovpn_nl_peer_float_notify

 Documentation/netlink/specs/ovpn.yaml       |  6 ++
 drivers/net/ovpn/netlink.c                  | 82 +++++++++++++++++++++
 drivers/net/ovpn/netlink.h                  |  2 +
 drivers/net/ovpn/peer.c                     |  2 +
 include/uapi/linux/ovpn.h                   |  1 +
 tools/testing/selftests/net/ovpn/ovpn-cli.c |  3 +
 6 files changed, 96 insertions(+)

diff --git a/Documentation/netlink/specs/ovpn.yaml 
b/Documentation/netlink/specs/ovpn.yaml
index 1b91045cee2e..0d0c028bf96f 100644
--- a/Documentation/netlink/specs/ovpn.yaml
+++ b/Documentation/netlink/specs/ovpn.yaml
@@ -502,6 +502,12 @@ operations:
             - ifindex
             - keyconf
 
+    -
+      name: peer-float-ntf
+      doc: Notification about a peer floating (changing its remote UDP 
endpoint)
+      notify: peer-get
+      mcgrp: peers
+
 mcast-groups:
   list:
     -
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index fed0e46b32a3..3db056f4cd0a 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -1203,6 +1203,88 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
        return ret;
 }
 
+/**
+ * ovpn_nl_float_peer_notify - notify userspace about peer floating
+ * @peer: the floated peer
+ * @ss: sockaddr representing the new remote endpoint
+ *
+ * Return: 0 on success or a negative error code otherwise
+ */
+int ovpn_nl_peer_float_notify(struct ovpn_peer *peer,
+                             const struct sockaddr_storage *ss)
+{
+       struct ovpn_socket *sock;
+       struct sockaddr_in6 *sa6;
+       struct sockaddr_in *sa;
+       struct sk_buff *msg;
+       struct nlattr *attr;
+       int ret = -EMSGSIZE;
+       void *hdr;
+
+       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_FLOAT_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_ID, peer->id))
+               goto err_cancel_msg;
+
+       if (ss->ss_family == AF_INET) {
+               sa = (struct sockaddr_in *)ss;
+               if (nla_put_in_addr(msg, OVPN_A_PEER_REMOTE_IPV4,
+                                   sa->sin_addr.s_addr) ||
+                   nla_put_net16(msg, OVPN_A_PEER_REMOTE_PORT, sa->sin_port))
+                       goto err_cancel_msg;
+       } else if (ss->ss_family == AF_INET6) {
+               sa6 = (struct sockaddr_in6 *)ss;
+               if (nla_put_in6_addr(msg, OVPN_A_PEER_REMOTE_IPV6,
+                                    &sa6->sin6_addr) ||
+                   nla_put_u32(msg, OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID,
+                               sa6->sin6_scope_id) ||
+                   nla_put_net16(msg, OVPN_A_PEER_REMOTE_PORT, sa6->sin6_port))
+                       goto err_cancel_msg;
+       } else {
+               ret = -EAFNOSUPPORT;
+               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->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
diff --git a/drivers/net/ovpn/netlink.h b/drivers/net/ovpn/netlink.h
index 8615dfc3c472..11ee7c681885 100644
--- a/drivers/net/ovpn/netlink.h
+++ b/drivers/net/ovpn/netlink.h
@@ -13,6 +13,8 @@ int ovpn_nl_register(void);
 void ovpn_nl_unregister(void);
 
 int ovpn_nl_peer_del_notify(struct ovpn_peer *peer);
+int ovpn_nl_peer_float_notify(struct ovpn_peer *peer,
+                             const struct sockaddr_storage *ss);
 int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id);
 
 #endif /* _NET_OVPN_NETLINK_H_ */
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index 4bfcab0c8652..9ad50f1ac2c3 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -287,6 +287,8 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, 
struct sk_buff *skb)
 
        spin_unlock_bh(&peer->lock);
 
+       ovpn_nl_peer_float_notify(peer, &ss);
+
        /* rehashing is required only in MP mode as P2P has one peer
         * only and thus there is no hashtable
         */
diff --git a/include/uapi/linux/ovpn.h b/include/uapi/linux/ovpn.h
index 680d1522dc87..b3c9ff0a6849 100644
--- a/include/uapi/linux/ovpn.h
+++ b/include/uapi/linux/ovpn.h
@@ -99,6 +99,7 @@ enum {
        OVPN_CMD_KEY_SWAP,
        OVPN_CMD_KEY_SWAP_NTF,
        OVPN_CMD_KEY_DEL,
+       OVPN_CMD_PEER_FLOAT_NTF,
 
        __OVPN_CMD_MAX,
        OVPN_CMD_MAX = (__OVPN_CMD_MAX - 1)
diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c 
b/tools/testing/selftests/net/ovpn/ovpn-cli.c
index 0a5226196a2e..064453d16fdd 100644
--- a/tools/testing/selftests/net/ovpn/ovpn-cli.c
+++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c
@@ -1516,6 +1516,9 @@ static int ovpn_handle_msg(struct nl_msg *msg, void *arg)
        case OVPN_CMD_PEER_DEL_NTF:
                fprintf(stdout, "received CMD_PEER_DEL_NTF\n");
                break;
+       case OVPN_CMD_PEER_FLOAT_NTF:
+               fprintf(stdout, "received CMD_PEER_FLOAT_NTF\n");
+               break;
        case OVPN_CMD_KEY_SWAP_NTF:
                fprintf(stdout, "received CMD_KEY_SWAP_NTF\n");
                break;
-- 
2.51.1



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

Reply via email to