Re: [RFC PATCH 2/2] platform: add support for WireGuard links



On Wed, 2018-03-14 at 00:03 +0000, Javier Arteaga wrote:
Add support for a new wireguard link type to the platform code. For
now
this only covers querying existing links via Generic Netlink and
parsing
them into platform objects.
---
 src/nm-types.h                   |   5 +
 src/platform/nm-linux-platform.c | 250
+++++++++++++++++++++++++++++++++++++++
 src/platform/nm-platform.c       |  97 +++++++++++++++
 src/platform/nm-platform.h       |  44 +++++++
 src/platform/nmp-object.c        |  25 ++++
 src/platform/nmp-object.h        |  21 ++++
 6 files changed, 442 insertions(+)

diff --git a/src/nm-types.h b/src/nm-types.h
index 239202cf4..d44cd0047 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -162,6 +162,7 @@ typedef enum {
      NM_LINK_TYPE_VETH,
      NM_LINK_TYPE_VLAN,
      NM_LINK_TYPE_VXLAN,
+     NM_LINK_TYPE_WIREGUARD,
 
      /* Software types with slaves */
      NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000,
@@ -193,6 +194,10 @@ typedef enum {
      NMP_OBJECT_TYPE_LNK_SIT,
      NMP_OBJECT_TYPE_LNK_VLAN,
      NMP_OBJECT_TYPE_LNK_VXLAN,
+     NMP_OBJECT_TYPE_LNK_WIREGUARD,
+
+     NMP_OBJECT_TYPE_WIREGUARD_PEER,
+     NMP_OBJECT_TYPE_WIREGUARD_ALLOWEDIP,

You ask whether peer/allowed-ip should be their own NMPObject
implementations. Maybe, but it's not stringend.

For example, NMPObjectLnkVlan embeds a pointer to the egress-qos-map,
and these map items are not individual "objects", they are just structs
in an C-array.
-- note that NMVlanQosMapping is not really more complex then
NMPlatformWireguardAllowedIP.
 
E.g.
https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nm-linux-platform.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n1475

Note that most NMPObject implementations are plain struct. The fact
that NMObjectLnkVlan is not, requires it to implement a special
clone/destroy function and special equal/hash.

https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nmp-object.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n2783


I think having them a separate object makes sense if you need things
like:
 - compare/hash individual instances 
 - to-string individual instances
 - share one instance (in general, NMPObject instances are supposed
   not to be changed after being created and shared (immutable) by
   taking references. Since NMPlatformWireguardAllowedIP and 
   NMPlatformWireguardPeer embed a CList item, they cannot be really
   shared either.

I tend to think they should not be own objects. If they are their own
NMPObject instances, they maybe should not be linked via an embedded
CList, beause it means they cannot be shared, which is a bit unusual
for these objects.

When receiving these objects, you also commonly get them all in one go,
like for the VLAN egress-qos-map. That is another reason why it doesn't
make much sense to have them individual objects. You can just allocate
one large array and put all the parsed structs inside.


      __NMP_OBJECT_TYPE_LAST,
      NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1,
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-
linux-platform.c
index f29ee03e6..eb73858bd 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -161,6 +161,40 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
 
 /*******************************************************************
**********/
 
+#define WG_CMD_GET_DEVICE 0
+#define WG_CMD_SET_DEVICE 1
+
+#define IFLA_WG_DEVICE_UNSPEC           0
+#define IFLA_WG_DEVICE_IFINDEX          1
+#define IFLA_WG_DEVICE_IFNAME           2
+#define IFLA_WG_DEVICE_PRIVATE_KEY      3
+#define IFLA_WG_DEVICE_PUBLIC_KEY       4
+#define IFLA_WG_DEVICE_FLAGS            5
+#define IFLA_WG_DEVICE_LISTEN_PORT      6
+#define IFLA_WG_DEVICE_FWMARK           7
+#define IFLA_WG_DEVICE_PEERS            8
+#define __IFLA_WG_DEVICE_MAX            9
+
+#define IFLA_WG_PEER_UNSPEC                        0
+#define IFLA_WG_PEER_PUBLIC_KEY                    1
+#define IFLA_WG_PEER_PRESHARED_KEY                 2
+#define IFLA_WG_PEER_FLAGS                         3
+#define IFLA_WG_PEER_ENDPOINT                      4
+#define IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL 5
+#define IFLA_WG_PEER_LAST_HANDSHAKE_TIME           6
+#define IFLA_WG_PEER_RX_BYTES                      7
+#define IFLA_WG_PEER_TX_BYTES                      8
+#define IFLA_WG_PEER_ALLOWEDIPS                    9
+#define __IFLA_WG_PEER_MAX                         10
+
+#define IFLA_WG_ALLOWEDIP_UNSPEC        0
+#define IFLA_WG_ALLOWEDIP_FAMILY        1
+#define IFLA_WG_ALLOWEDIP_IPADDR        2
+#define IFLA_WG_ALLOWEDIP_CIDR_MASK     3
+#define __IFLA_WG_ALLOWEDIP_MAX         4
+
+/*******************************************************************
**********/
+
 #define _NMLOG_PREFIX_NAME                "platform-linux"
 #define _NMLOG_DOMAIN                     LOGD_PLATFORM
 #define _NMLOG2_DOMAIN                    LOGD_PLATFORM
@@ -543,6 +577,7 @@ static const LinkDesc linktypes[] = {
      {
NM_LINK_TYPE_VETH,          "veth",        "veth",        NULL },
      {
NM_LINK_TYPE_VLAN,          "vlan",        "vlan",        "vlan" },
      {
NM_LINK_TYPE_VXLAN,         "vxlan",       "vxlan",       "vxlan" },
+     {
NM_LINK_TYPE_WIREGUARD,     "wireguard",   "wireguard",   "wireguard"
},
 
      {
NM_LINK_TYPE_BRIDGE,        "bridge",      "bridge",      "bridge" },
      {
NM_LINK_TYPE_BOND,          "bond",        "bond",        "bond" },
@@ -1377,6 +1412,218 @@ _parse_lnk_sit (const char *kind, struct
nlattr *info_data)
 
 /*******************************************************************
**********/
 
+static int
+_wireguard_parse_allowedip (struct nlattr *allowedip_attr, CList
*list_head)
+{
+     static const struct nla_policy
allowedip_policy[__IFLA_WG_ALLOWEDIP_MAX] = {
+             [IFLA_WG_ALLOWEDIP_FAMILY]    = { .type = NLA_U16 },
+             [IFLA_WG_ALLOWEDIP_IPADDR]    = { .minlen = sizeof
(struct in_addr) },
+             [IFLA_WG_ALLOWEDIP_CIDR_MASK] = { .type = NLA_U8 },
+     };
+     struct nlattr *tba[__IFLA_WG_ALLOWEDIP_MAX];
+     NMPObject *obj;
+     NMPlatformWireguardAllowedIP *allowedip;
+     int addr_len;
+     int ret;
+
+     ret = nla_parse_nested (tba, __IFLA_WG_ALLOWEDIP_MAX,
allowedip_attr, allowedip_policy);
+     if (ret)
+             goto errout;
+
+     obj = nmp_object_new (NMP_OBJECT_TYPE_WIREGUARD_ALLOWEDIP,
NULL);
+     allowedip = &obj->wireguard_allowedip;
+
+     allowedip->family = tba[IFLA_WG_ALLOWEDIP_FAMILY] ?
nla_get_u16 (tba[IFLA_WG_ALLOWEDIP_FAMILY]) : 0;
+
+     addr_len = (allowedip->family == AF_INET)

check that the family is at least AF_INET6, otherwise error out.

+                ? sizeof (in_addr_t)
+                : sizeof (struct in6_addr);
+
+     ret = -NLE_ATTRSIZE;
+     _check_addr_or_errout (tba, IFLA_WG_ALLOWEDIP_IPADDR,
addr_len);
+     if (tba[IFLA_WG_ALLOWEDIP_IPADDR])
+             memcpy (&allowedip->ip, nla_data
(tba[IFLA_WG_ALLOWEDIP_IPADDR]), addr_len);
+
+     allowedip->cidr = tba[IFLA_WG_ALLOWEDIP_CIDR_MASK] ?
nla_get_u8 (tba[IFLA_WG_ALLOWEDIP_CIDR_MASK]) : 0;
+
+     c_list_link_tail (list_head, &allowedip->allowedips_lst);
+
+     ret = 0;
+errout:
+     return ret;
+}
+
+static int
+_wireguard_parse_peer (struct nlattr *peer_attr, CList *list_head)
+{
+     static const struct nla_policy
peer_policy[__IFLA_WG_PEER_MAX] = {
+             [IFLA_WG_PEER_PUBLIC_KEY]                    = {
.minlen = NM_WG_PUBLIC_KEY_LEN },
+             [IFLA_WG_PEER_PRESHARED_KEY]                 = {
.minlen = NM_WG_SYMMETRIC_KEY_LEN },
+             [IFLA_WG_PEER_FLAGS]                         = {
.type = NLA_U32 },
+             [IFLA_WG_PEER_ENDPOINT]                      = {
.minlen = sizeof (struct sockaddr) },
+             [IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL] = {
.type = NLA_U16 },
+             [IFLA_WG_PEER_LAST_HANDSHAKE_TIME]           = {
.minlen = sizeof (struct timespec) },
+             [IFLA_WG_PEER_RX_BYTES]                      = {
.type = NLA_U64 },
+             [IFLA_WG_PEER_TX_BYTES]                      = {
.type = NLA_U64 },
+             [IFLA_WG_PEER_ALLOWEDIPS]                    = {
.type = NLA_NESTED },
+     };
+     struct nlattr *tbp[__IFLA_WG_PEER_MAX];
+     NMPObject *obj;
+     NMPlatformWireguardPeer *peer;
+     int ret;
+
+     ret = nla_parse_nested (tbp, __IFLA_WG_PEER_MAX, peer_attr,
peer_policy);
+     if (ret)
+             goto errout;
+
+     obj = nmp_object_new (NMP_OBJECT_TYPE_WIREGUARD_PEER, NULL);
+     peer = &obj->wireguard_peer;
+
+     if (tbp[IFLA_WG_PEER_PUBLIC_KEY])
+             memcpy (&peer->public_key, nla_data
(tbp[IFLA_WG_PEER_PUBLIC_KEY]), sizeof (peer->public_key));
+
+     if (tbp[IFLA_WG_PEER_PRESHARED_KEY])
+             memcpy (&peer->preshared_key, nla_data
(tbp[IFLA_WG_PEER_PRESHARED_KEY]), sizeof (peer->preshared_key));
+
+     if (tbp[IFLA_WG_PEER_ENDPOINT])
+             memcpy (&peer->endpoint, nla_data
(tbp[IFLA_WG_PEER_ENDPOINT]), sizeof (peer->endpoint));
+
+     peer->persistent_keepalive_interval =
tbp[IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL] ? nla_get_u64
(tbp[IFLA_WG_PEER_PERSISTENT_KEEPALIVE_INTERVAL]) : 0;
+
+     if (tbp[IFLA_WG_PEER_LAST_HANDSHAKE_TIME])
+             memcpy (&peer->last_handshake_time, nla_data
(tbp[IFLA_WG_PEER_LAST_HANDSHAKE_TIME]), sizeof (peer-
last_handshake_time));
+
+     peer->rx_bytes = tbp[IFLA_WG_PEER_RX_BYTES] ? nla_get_u64
(tbp[IFLA_WG_PEER_RX_BYTES]) : 0;
+     peer->tx_bytes = tbp[IFLA_WG_PEER_TX_BYTES] ? nla_get_u64
(tbp[IFLA_WG_PEER_TX_BYTES]) : 0;
+
+     c_list_init (&peer->allowedips_lst_head);
+     if (tbp[IFLA_WG_PEER_ALLOWEDIPS]) {
+             struct nlattr *allowedip_attr;
+             int remaining_allowedips;
+             nla_for_each_nested (allowedip_attr,
tbp[IFLA_WG_PEER_ALLOWEDIPS], remaining_allowedips) {
+                     ret = _wireguard_parse_allowedip
(allowedip_attr, &peer->allowedips_lst_head);
+                     if (ret)
+                             goto errout;
+             }
+     }
+
+     c_list_link_tail (list_head, &peer->peers_lst);
+
+     ret = 0;
+errout:
+     return ret;
+}
+
+static int
+_wireguard_parse_getdevice (struct nl_msg *msg, void *arg)
+{
+     static const struct nla_policy
device_policy[__IFLA_WG_DEVICE_MAX] = {
+             [IFLA_WG_DEVICE_IFINDEX]     = { .type = NLA_U32 },
+             [IFLA_WG_DEVICE_IFNAME]      = { .type =
NLA_NUL_STRING, .maxlen = IFNAMSIZ - 1 },
+             [IFLA_WG_DEVICE_PRIVATE_KEY] = { .minlen =
NM_WG_PUBLIC_KEY_LEN },
+             [IFLA_WG_DEVICE_PUBLIC_KEY]  = { .minlen =
NM_WG_PUBLIC_KEY_LEN },
+             [IFLA_WG_DEVICE_FLAGS]       = { .type = NLA_U32 },
+             [IFLA_WG_DEVICE_LISTEN_PORT] = { .type = NLA_U16 },
+             [IFLA_WG_DEVICE_FWMARK]      = { .type = NLA_U32 },
+             [IFLA_WG_DEVICE_PEERS]       = { .type = NLA_NESTED
},
+     };
+     struct nlattr *tbd[__IFLA_WG_DEVICE_MAX];
+     NMPObject *obj = * (NMPObject **) arg;
+     NMPlatformLnkWireguard *props;
+     struct nlmsghdr *nlh = nlmsg_hdr (msg);
+     int ret;
+
+     ret = genlmsg_parse (nlh, 0, tbd, __IFLA_WG_DEVICE_MAX - 1,
device_policy);
+     if (ret)
+             goto errout;
+
+     props = &obj->lnk_wireguard;
+
+     props->listen_port = tbd[IFLA_WG_DEVICE_LISTEN_PORT] ?
nla_get_u16 (tbd[IFLA_WG_DEVICE_LISTEN_PORT]) : 0;
+     props->fwmark = tbd[IFLA_WG_DEVICE_FWMARK] ? nla_get_u32
(tbd[IFLA_WG_DEVICE_FWMARK]) : 0;
+
+     if (tbd[IFLA_WG_DEVICE_PRIVATE_KEY])
+             nla_memcpy (props->private_key,
tbd[IFLA_WG_DEVICE_PRIVATE_KEY], sizeof (props->private_key));
+     else
+             memset (props->private_key, 0, sizeof (props-
private_key));
+
+     if (tbd[IFLA_WG_DEVICE_PUBLIC_KEY])
+             nla_memcpy (props->public_key,
tbd[IFLA_WG_DEVICE_PUBLIC_KEY], sizeof (props->public_key));
+     else
+             memset (props->public_key, 0, sizeof (props-
public_key));
+
+     c_list_init (&props->peers_lst_head);
+     if (tbd[IFLA_WG_DEVICE_PEERS]) {
+             struct nlattr *peer_attr;
+             int remaining_peers;
+             nla_for_each_nested (peer_attr,
tbd[IFLA_WG_DEVICE_PEERS], remaining_peers) {
+                     ret = _wireguard_parse_peer (peer_attr,
&props->peers_lst_head);
+                     if (ret)
+                             goto errout;
+             }
+     }
+
+     return NL_STOP;
+errout:
+     return NL_SKIP;
+}
+
+static NMPObject *
+_parse_lnk_wireguard (const char *kind, const char *ifname)
+{
+     nm_auto_nmpobj NMPObject *obj = NULL;
+     NMPObject *obj_result = NULL;
+     struct nl_sock *sock;
+     nm_auto_nlmsg struct nl_msg *msg = NULL;
+     struct nl_cb cb = {
+             .valid_cb = _wireguard_parse_getdevice,
+     };
+     static int family_id;
+
+     if (!nm_streq0 (kind, "wireguard"))
+             goto err;
+
+     sock = nl_socket_alloc ();
+     if (!sock)
+             goto err;
+
+     if (nl_connect (sock, NETLINK_GENERIC))

I think the genl socket should be cached and re-used by
NMLinuxPlatform. Likewise, family_id should be cached in
NMLinuxPlatformPrivate.


+             goto err_socket;

It's a bit odd that _parse_lnk_wireguard() opens a genl socket to
request additional data. Commonly the entire parsing of
_new_from_nl_link() is only supposed to get information that is present
in the netlink message. They only thing that they might do, is look
into the platform cache, and re-use information from there, for example
at
https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nm-linux-platform.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n785
https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nm-linux-platform.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n1833

Basically, for every RTM_NEWLINK event, it re-fetches all wireguard
information from genetlink. That seems a bit heavy. Do we get a
notification on (ge)netlink when something about this interface
changes?

Otherwise, you could just look into the platform cache, see that the
information is already, and re-use it from there.


+
+     if (!family_id)
+             family_id = genl_ctrl_resolve (sock, "wireguard");
+     if (family_id <= 0)
+             goto err_socket;
+
+     msg = nlmsg_alloc ();
+
+     if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id,
+                       0, NLM_F_DUMP, WG_CMD_GET_DEVICE, 1))
+             goto err_socket;
+
+     if (nla_put_string (msg, IFLA_WG_DEVICE_IFNAME, ifname) < 0)

can we avoid lookup by ifname? The ifname can be changed, only ifindex
is the unchangable, unique ID (mostly, not really either :( )

+             goto err_socket;
+
+     if (nl_send_auto (sock, msg) < 0)
+             goto err_socket;
+
+     obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
+     cb.valid_arg = &obj;
+
+     if (nl_recvmsgs (sock, &cb) < 0)
+             goto err_socket;
+
+     obj_result = obj;
+     obj = NULL;
+
+err_socket:
+     nl_socket_free (sock);
+err:
+     return obj_result;
+}
+
+/*******************************************************************
**********/
+
 static gboolean
 _vlan_qos_mapping_from_nla (struct nlattr *nlattr,
                             const NMVlanQosMapping **out_map,
@@ -1814,6 +2061,9 @@ _new_from_nl_link (NMPlatform *platform, const
NMPCache *cache, struct nlmsghdr
      case NM_LINK_TYPE_VXLAN:
              lnk_data = _parse_lnk_vxlan (nl_info_kind,
nl_info_data);
              break;
+     case NM_LINK_TYPE_WIREGUARD:
+             lnk_data = _parse_lnk_wireguard (nl_info_kind, obj-
link.name);
+             break;
      default:
              lnk_data_complete_from_cache = FALSE;
              break;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 7e2f27ced..2d631c7ca 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -27,6 +27,8 @@
 #include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
 #include <string.h>
 #include <linux/ip.h>
 #include <linux/if_tun.h>
@@ -1906,6 +1908,12 @@ nm_platform_link_get_lnk_vxlan (NMPlatform
*self, int ifindex, const NMPlatformL
      return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN,
out_link);
 }
 
+const NMPlatformLnkWireguard *
+nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex,
const NMPlatformLink **out_link)
+{
+     return _link_get_lnk (self, ifindex, NM_LINK_TYPE_WIREGUARD,
out_link);
+}
+
 /*******************************************************************
**********/
 
 /**
@@ -4994,6 +5002,95 @@ nm_platform_lnk_sit_to_string (const
NMPlatformLnkSit *lnk, char *buf, gsize len
      return buf;
 }
 
+const char *
+nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireguard
*lnk, char *buf, gsize len)
+{
+     gchar *public_b64;
+     if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+             return buf;
+
+     public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk-
public_key));
+
+     g_snprintf (buf, len,
+                 "wireguard "
+                 "public_key %s "
+                 "private_key (hidden) "
+                 "listen_port %u "
+                 "fwmark 0x%x",
+                 public_b64,
+                 lnk->listen_port,
+                 lnk->fwmark);
+
+     g_free (public_b64);

don't explicitly free. Use one of the gs_* or nm_auto_* macros.
In this case, gs_free.

Commonly, the to-string methods should print *all* aspects of the
object. It's right to hide the private-key, I am talking about the
Peers/AllowedIPs.

The sole purpose of the to-string methods if for debugging. Currently,
the peers/allowed-ips are never printed, maybe they should.

Note also that nmp_object_to_string() has an arguemnt to_string_mode,
for printing common fields (NMP_OBJECT_TO_STRING_PUBLIC) vs. all
(NMP_OBJECT_TO_STRING_ALL).
I think at least for NMP_OBJECT_TO_STRING_ALL, NMPObjectLnkWireguard
should print all peers/allowed-ips. This means to implement
"cmd_obj_to_string".
See 
https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/platform/nmp-object.c?id=167e42a87e97ed7fb26a4263c22f1774716ac51b#n666


+
+     return buf;
+}
+
+const char *
+nm_platform_wireguard_peer_to_string (const NMPlatformWireguardPeer
*peer, char *buf, gsize len)
+{
+     gchar *public_b64;
+     char s_endpoint[NI_MAXHOST + NI_MAXSERV + sizeof("endpoint
[]:") + 1];
+
+     if (!nm_utils_to_string_buffer_init_null (peer, &buf, &len))
+             return buf;
+
+     if (peer->endpoint.addr.sa_family == AF_INET || peer-
endpoint.addr.sa_family == AF_INET6) {
+             char host[NI_MAXHOST];
+             char service[NI_MAXSERV];
+             socklen_t addr_len = 0;
+
+             if (peer->endpoint.addr.sa_family == AF_INET)
+                     addr_len = sizeof (struct sockaddr_in);
+             else if (peer->endpoint.addr.sa_family == AF_INET6)
+                     addr_len = sizeof (struct sockaddr_in6);
+             if (!getnameinfo (&peer->endpoint.addr, addr_len,
host, sizeof(host), service, sizeof(service), NI_DGRAM |
NI_NUMERICSERV | NI_NUMERICHOST)) {

I don't think we should resolve the addresses just for logging.
Just convert them to string with nm_utils_inet_ntop().


+                     if (peer->endpoint.addr.sa_family ==
AF_INET6 && strchr (host, ':'))
+                             g_snprintf(s_endpoint, sizeof
(s_endpoint), "endpoint [%s]:%s ", host, service);
+                     else
+                             g_snprintf(s_endpoint, sizeof
(s_endpoint), "endpoint %s:%s ", host, service);
+             }
+     } else {
+             s_endpoint[0] = '\0';
+     }
+
+     public_b64 = g_base64_encode (peer->public_key, sizeof
(peer->public_key));
+
+     g_snprintf (buf, len,
+                 "wgpeer "
+                 "public_key %s "
+                 "preshared_key (hidden) "
+                 "%s" /* endpoint */
+                 "rx %"G_GUINT64_FORMAT" "
+                 "tx %"G_GUINT64_FORMAT"",
+                 public_b64,
+                 s_endpoint,
+                 peer->rx_bytes,
+                 peer->tx_bytes);
+
+     g_free (public_b64);
+
+     return buf;
+}
+
+const char *
+nm_platform_wireguard_allowedip_to_string (const
NMPlatformWireguardAllowedIP *allowedip, char *buf, gsize len)
+{
+     char s_address[INET_ADDRSTRLEN];
+
+     if (!nm_utils_to_string_buffer_init_null (allowedip, &buf,
&len))
+             return buf;
+
+     inet_ntop (allowedip->family, &allowedip->ip, s_address,
sizeof(s_address));
+
+     g_snprintf (buf, len,
+                 "wgallowedip %s/%u",
+                 s_address,
+                 allowedip->cidr);
+
+     return buf;
+}
+
 const char *
 nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char
*buf, gsize len)
 {
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 53b2975bf..a8cf7bfd4 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -30,6 +30,7 @@
 #include "nm-dbus-interface.h"
 #include "nm-core-types-internal.h"
 
+#include "nm-utils/c-list.h"
 #include "nm-core-utils.h"
 #include "nm-setting-vlan.h"
 #include "nm-setting-wired.h"
@@ -80,6 +81,9 @@ typedef gboolean (*NMPObjectPredicateFunc) (const
NMPObject *obj,
 /* Redefine this in host's endianness */
 #define NM_GRE_KEY      0x2000
 
+#define NM_WG_PUBLIC_KEY_LEN    32
+#define NM_WG_SYMMETRIC_KEY_LEN 32
+
 typedef enum {
      /* use our own platform enum for the nlmsg-flags. Otherwise,
we'd have
       * to include <linux/netlink.h> */
@@ -682,6 +686,42 @@ typedef struct {
      bool l3miss:1;
 } NMPlatformLnkVxlan;
 
+typedef struct {
+     guint16 family;
+     union {
+             struct in_addr ip4;
+             struct in6_addr ip6;
+     } ip;
+     guint8 cidr;
+
+     CList allowedips_lst;
+} NMPlatformWireguardAllowedIP;
+
+typedef struct {
+     guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
+     guint8 preshared_key[NM_WG_SYMMETRIC_KEY_LEN];
+     union {
+             struct sockaddr addr;
+             struct sockaddr_in addr4;
+             struct sockaddr_in6 addr6;
+     } endpoint;
+     struct timespec last_handshake_time;
+     guint64 rx_bytes, tx_bytes;
+     guint16 persistent_keepalive_interval;
+
+     CList peers_lst;
+     CList allowedips_lst_head;
+} NMPlatformWireguardPeer;
+
+typedef struct {
+     guint8 private_key[NM_WG_PUBLIC_KEY_LEN];
+     guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
+     guint16 listen_port;
+     guint32 fwmark;
+
+     CList peers_lst_head;

The public part of the NMPObjects (NMPlatformLnkWireguard vs.
NMPObjectLnkWireguard) is supposed to be copyable directly. That means,
it cannot have pointers (except for example NMPlatformLink.kind, which
is however a static string, so it's safe to copy).

This means, the CList part must go into NMPObjectLnkWireguard.


Together with I said above about nm_platform_lnk_wireguard_to_string()
to print all fields, it means, the list of peers/allowed-ips is not
accessible to NMPlatformLnkWireguard, so there is nothing to print.
But it certainly should implement cmd_obj_to_string().

+} NMPlatformLnkWireguard;
+
 typedef struct {
      gint64 owner;
      gint64 group;
@@ -1161,6 +1201,7 @@ const NMPlatformLnkMacvtap
*nm_platform_link_get_lnk_macvtap (NMPlatform *self,
 const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform
*self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform
*self, int ifindex, const NMPlatformLink **out_link);
 const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform
*self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkWireguard *nm_platform_link_get_lnk_wireguard
(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
 
 NMPlatformError nm_platform_link_vlan_add (NMPlatform *self,
                                            const char *name,
@@ -1339,6 +1380,9 @@ const char *nm_platform_lnk_macvlan_to_string
(const NMPlatformLnkMacvlan *lnk,
 const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit
*lnk, char *buf, gsize len);
 const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan
*lnk, char *buf, gsize len);
 const char *nm_platform_lnk_vxlan_to_string (const
NMPlatformLnkVxlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_wireguard_to_string (const
NMPlatformLnkWireguard *lnk, char *buf, gsize len);
+const char *nm_platform_wireguard_peer_to_string (const
NMPlatformWireguardPeer *peer, char *buf, gsize len);
+const char *nm_platform_wireguard_allowedip_to_string (const
NMPlatformWireguardAllowedIP *peer, char *buf, gsize len);
 const char *nm_platform_ip4_address_to_string (const
NMPlatformIP4Address *address, char *buf, gsize len);
 const char *nm_platform_ip6_address_to_string (const
NMPlatformIP6Address *address, char *buf, gsize len);
 const char *nm_platform_ip4_route_to_string (const
NMPlatformIP4Route *route, char *buf, gsize len);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 4df64e608..06883c57b 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -2807,5 +2807,30 @@ const NMPClass
_nmp_classes[NMP_OBJECT_TYPE_MAX] = {
              .cmd_plobj_hash_update              = (void (*)
(const NMPlatformObject *obj, NMHashState *h))
nm_platform_lnk_vxlan_hash_update,
              .cmd_plobj_cmp                      = (int (*)
(const NMPlatformObject *obj1, const NMPlatformObject *obj2))
nm_platform_lnk_vxlan_cmp,
      },
+     [NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = {
+             .parent                             =
DEDUP_MULTI_OBJ_CLASS_INIT(),
+             .obj_type                           =
NMP_OBJECT_TYPE_LNK_WIREGUARD,
+             .sizeof_data                        = sizeof
(NMPObjectLnkWireguard),
+             .sizeof_public                      = sizeof
(NMPlatformLnkWireguard),
+             .obj_type_name                      = "wireguard",
+             .lnk_link_type                      =
NM_LINK_TYPE_WIREGUARD,
+             .cmd_plobj_to_string                = (const char
*(*) (const NMPlatformObject *obj, char *buf, gsize len)) 

the types that are put inside the platform cache (like
NMPObjectLnkWireguard), they must implement equality/hash operators.

NMPObjectLnkWireguard is not unlike NMPObjectLnkVlan. See what
functions are implemented there.


nm_platform_lnk_wireguard_to_string,
+     },
+     [NMP_OBJECT_TYPE_WIREGUARD_PEER - 1] = {
+             .parent                             =
DEDUP_MULTI_OBJ_CLASS_INIT(),
+             .obj_type                           =
NMP_OBJECT_TYPE_WIREGUARD_PEER,
+             .sizeof_data                        = sizeof
(NMPObjectWireguardPeer),
+             .sizeof_public                      = sizeof
(NMPlatformWireguardPeer),
+             .obj_type_name                      = "wireguard-
peer",
+             .cmd_plobj_to_string                = (const char
*(*) (const NMPlatformObject *obj, char *buf, gsize len))
nm_platform_wireguard_peer_to_string,
+     },
+     [NMP_OBJECT_TYPE_WIREGUARD_ALLOWEDIP - 1] = {
+             .parent                             =
DEDUP_MULTI_OBJ_CLASS_INIT(),
+             .obj_type                           =
NMP_OBJECT_TYPE_WIREGUARD_ALLOWEDIP,
+             .sizeof_data                        = sizeof
(NMPObjectWireguardAllowedIP),
+             .sizeof_public                      = sizeof
(NMPlatformWireguardAllowedIP),
+             .obj_type_name                      = "wireguard-
allowedip",
+             .cmd_plobj_to_string                = (const char
*(*) (const NMPlatformObject *obj, char *buf, gsize len))
nm_platform_wireguard_allowedip_to_string,
+     },
 };
 
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index 8c36e2e3d..afa504f9c 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -209,6 +209,18 @@ typedef struct {
      NMPlatformLnkVxlan _public;
 } NMPObjectLnkVxlan;
 
+typedef struct {
+     NMPlatformLnkWireguard _public;
+} NMPObjectLnkWireguard;
+
+typedef struct {
+     NMPlatformWireguardPeer _public;
+} NMPObjectWireguardPeer;
+
+typedef struct {
+     NMPlatformWireguardAllowedIP _public;
+} NMPObjectWireguardAllowedIP;
+
 typedef struct {
      NMPlatformIP4Address _public;
 } NMPObjectIP4Address;
@@ -271,6 +283,15 @@ struct _NMPObject {
              NMPlatformLnkVxlan      lnk_vxlan;
              NMPObjectLnkVxlan       _lnk_vxlan;
 
+             NMPlatformLnkWireguard  lnk_wireguard;
+             NMPObjectLnkWireguard   _lnk_wireguard;
+
+             NMPlatformWireguardPeer wireguard_peer;
+             NMPObjectWireguardPeer  _wireguard_peer;
+
+             NMPlatformWireguardAllowedIP wireguard_allowedip;
+             NMPObjectWireguardAllowedIP  _wireguard_allowedip;
+
              NMPlatformIPAddress     ip_address;
              NMPlatformIPXAddress    ipx_address;
              NMPlatformIP4Address    ip4_address;

Attachment: signature.asc
Description: This is a digitally signed message part



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]