Attention is currently required from: plaisthos.
Hello plaisthos,
I'd like you to do a code review.
Please visit
http://gerrit.openvpn.net/c/openvpn/+/1734?usp=email
to review the following change.
Change subject: Support pre-existing Linux DCO interfaces
......................................................................
Support pre-existing Linux DCO interfaces
When creating an ovpn interface returns -EEXIST, still retrieve the
ifindex and return the error to the generic DCO open path. This lets the
caller mark the interface as pre-existing and avoid deleting it on
close.
Before accepting the existing interface, query its rtnetlink link info
and verify that it is an ovpn device with the expected mode. The ovpn
mode is fixed at interface creation time, so attaching to an interface
created for the other mode cannot work.
Honor the pre-existing state on close by skipping net_iface_del() for
persistent interfaces.
Github: closes OpenVPN/openvpn#1064
Change-Id: I72302403bddee4b0b0ee2441ae9e246f48d0bc81
Signed-off-by: Ralf Lici <[email protected]>
---
M src/openvpn/dco.h
M src/openvpn/dco_linux.c
M src/openvpn/networking.h
M src/openvpn/networking_iproute2.c
M src/openvpn/networking_sitnl.c
5 files changed, 144 insertions(+), 7 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/34/1734/1
diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h
index 4e5aad5..4584004 100644
--- a/src/openvpn/dco.h
+++ b/src/openvpn/dco.h
@@ -109,7 +109,8 @@
bool ovpn_dco_init(struct context *c);
/**
- * Open/create a DCO interface
+ * Open/create a DCO interface and store its ifindex.
+ * If the interface already exists, save the ifindex anyway and return -EEXIST.
*
* @param tt the tuntap context
* @param ctx the networking API context
diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c
index 40746bd..2eedbf8 100644
--- a/src/openvpn/dco_linux.c
+++ b/src/openvpn/dco_linux.c
@@ -508,11 +508,31 @@
ASSERT(tt->type == DEV_TYPE_TUN);
int ret = net_iface_new(ctx, dev, OVPN_FAMILY_NAME, &tt->dco);
- if (ret < 0)
+ if (ret < 0 && ret != -EEXIST)
{
msg(D_DCO_DEBUG, "Cannot create DCO interface %s: %d", dev, ret);
return ret;
}
+ else if (ret == -EEXIST)
+ {
+ const char *expected = tt->dco.ifmode == OVPN_MODE_MP ? "server" :
"p2p";
+ uint8_t mode;
+ int mode_ret = net_iface_ovpn_mode(ctx, dev, &mode);
+
+ if (mode_ret < 0)
+ {
+ msg(M_WARN, "DCO: cannot retrieve mode of existing interface %s:
%s (%d)", dev,
+ strerror(-mode_ret), mode_ret);
+ return mode_ret;
+ }
+
+ if (mode != (uint8_t)tt->dco.ifmode)
+ {
+ msg(M_WARN, "DCO: existing interface %s is in %s mode, expected %s
mode", dev,
+ mode == OVPN_MODE_MP ? "server" : "p2p", expected);
+ return -EINVAL;
+ }
+ }
tt->dco.ifindex = if_nametoindex(dev);
if (!tt->dco.ifindex)
@@ -520,7 +540,7 @@
msg(M_FATAL, "DCO: cannot retrieve ifindex for interface %s", dev);
}
- return 0;
+ return ret;
}
void
@@ -528,7 +548,10 @@
{
msg(D_DCO_DEBUG, __func__);
- net_iface_del(ctx, tt->actual_name);
+ if (!tt->persistent_if)
+ {
+ net_iface_del(ctx, tt->actual_name);
+ }
ovpn_dco_uninit_netlink(&tt->dco);
}
diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h
index bce0c19..b74d448 100644
--- a/src/openvpn/networking.h
+++ b/src/openvpn/networking.h
@@ -115,6 +115,19 @@
*/
int net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, char
type[IFACE_TYPE_LEN_MAX]);
+#if defined(ENABLE_DCO) && defined(TARGET_LINUX)
+/**
+ * Retrieve the ovpn interface mode
+ *
+ * @param ctx the implementation specific context
+ * @param iface interface to query
+ * @param mode variable where the ovpn mode attribute will be stored
+ *
+ * @return 0 on success, a negative error code otherwise
+ */
+int net_iface_ovpn_mode(openvpn_net_ctx_t *ctx, const char *iface, uint8_t
*mode);
+#endif
+
/**
* Remove an interface
*
diff --git a/src/openvpn/networking_iproute2.c
b/src/openvpn/networking_iproute2.c
index a1f3525..8105dcb 100644
--- a/src/openvpn/networking_iproute2.c
+++ b/src/openvpn/networking_iproute2.c
@@ -82,6 +82,16 @@
return -1;
}
+#if defined(ENABLE_DCO)
+int
+net_iface_ovpn_mode(openvpn_net_ctx_t *ctx, const char *iface, uint8_t *mode)
+{
+ /* not supported by iproute2 */
+ msg(M_WARN, "%s: operation not supported by iproute2 backend", __func__);
+ return -EOPNOTSUPP;
+}
+#endif
+
int
net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
{
diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c
index b3f8e2b..3c462c9 100644
--- a/src/openvpn/networking_sitnl.c
+++ b/src/openvpn/networking_sitnl.c
@@ -1412,8 +1412,18 @@
return 0;
}
-int
-net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, char
type[IFACE_TYPE_LEN_MAX])
+/**
+ * Issue an RTM_GETLINK query for an interface and feed the reply to the given
+ * parsing callback.
+ *
+ * @param iface name of the interface to query
+ * @param cb callback invoked with the netlink reply
+ * @param arg opaque argument passed through to the callback
+ *
+ * @return 0 on success, a negative error code otherwise
+ */
+static int
+sitnl_link_get(const char *iface, sitnl_parse_reply_cb cb, void *arg)
{
struct sitnl_link_req req = {};
int ifindex = if_nametoindex(iface);
@@ -1430,9 +1440,15 @@
req.i.ifi_family = AF_PACKET;
req.i.ifi_index = ifindex;
+ return sitnl_send(&req.n, 0, 0, cb, arg);
+}
+
+int
+net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, char
type[IFACE_TYPE_LEN_MAX])
+{
memset(type, 0, IFACE_TYPE_LEN_MAX);
- int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
+ int ret = sitnl_link_get(iface, sitnl_type_save, type);
if (ret < 0)
{
msg(D_ROUTE, "%s: cannot retrieve iface %s: %s (%d)", __func__, iface,
strerror(-ret), ret);
@@ -1444,6 +1460,80 @@
return 0;
}
+#if defined(ENABLE_DCO)
+static int
+sitnl_ovpn_mode_save(struct nlmsghdr *n, void *arg)
+{
+ uint8_t *mode = arg;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct rtattr *tb_link[IFLA_INFO_MAX + 1];
+ struct rtattr *tb_data[IFLA_OVPN_MAX + 1];
+
+ if (n->nlmsg_type != RTM_NEWLINK)
+ {
+ return -EINVAL;
+ }
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
+ {
+ return -EINVAL;
+ }
+
+ sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+ if (!tb[IFLA_LINKINFO])
+ {
+ return -ENOENT;
+ }
+
+ sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!tb_link[IFLA_INFO_KIND]
+ || strcmp(RTA_DATA(tb_link[IFLA_INFO_KIND]), OVPN_FAMILY_NAME) != 0)
+ {
+ return -EINVAL;
+ }
+
+ if (!tb_link[IFLA_INFO_DATA])
+ {
+ return -ENOENT;
+ }
+
+ sitnl_parse_rtattr_nested(tb_data, IFLA_OVPN_MAX, tb_link[IFLA_INFO_DATA]);
+
+ if (!tb_data[IFLA_OVPN_MODE])
+ {
+ return -ENOENT;
+ }
+
+ if (RTA_PAYLOAD(tb_data[IFLA_OVPN_MODE]) < sizeof(*mode))
+ {
+ return -EINVAL;
+ }
+
+ *mode = *(uint8_t *)RTA_DATA(tb_data[IFLA_OVPN_MODE]);
+
+ return 0;
+}
+
+int
+net_iface_ovpn_mode(openvpn_net_ctx_t *ctx, const char *iface, uint8_t *mode)
+{
+ int ret = sitnl_link_get(iface, sitnl_ovpn_mode_save, mode);
+ if (ret < 0)
+ {
+ msg(D_ROUTE, "%s: cannot retrieve ovpn mode for iface %s: %s (%d)",
__func__, iface,
+ strerror(-ret), ret);
+ return ret;
+ }
+
+ msg(D_ROUTE, "%s: mode of %s: %u", __func__, iface, *mode);
+
+ return 0;
+}
+#endif /* defined(ENABLE_DCO) */
+
int
net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
{
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1734?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I72302403bddee4b0b0ee2441ae9e246f48d0bc81
Gerrit-Change-Number: 1734
Gerrit-PatchSet: 1
Gerrit-Owner: ralf_lici <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel