From patchwork Sun Jul 10 22:10:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2578 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id kFwECifby2KZRwAAIUCqbw (envelope-from ) for ; Mon, 11 Jul 2022 04:11:19 -0400 Received: from proxy8.mail.ord1c.rsapps.net ([172.28.255.1]) by director9.mail.ord1d.rsapps.net with LMTP id QIaeCSfby2KpWwAAalYnBA (envelope-from ) for ; Mon, 11 Jul 2022 04:11:19 -0400 Received: from smtp23.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy8.mail.ord1c.rsapps.net with LMTPS id SNtfCSfby2LRcAAAHz/atg (envelope-from ) for ; Mon, 11 Jul 2022 04:11:19 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp23.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 0a657940-00f1-11ed-91e7-b8ca3a678528-1-1 Received: from [216.105.38.7] ([216.105.38.7:50230] helo=lists.sourceforge.net) by smtp23.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 0E/AD-01526-62BDBC26; Mon, 11 Jul 2022 04:11:18 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1oAoUb-0003yK-II; Mon, 11 Jul 2022 08:10:08 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1oAoUT-0003xs-L9 for openvpn-devel@lists.sourceforge.net; Mon, 11 Jul 2022 08:10:00 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=T9ULc9TIG3opxmuyGee3mcp6NGXuFv7wayJE4IT+Pnc=; b=eVOOIfgCHmbxv97UN9nDOVqJ2p umr3H4/GsjrO+p86H0ue8CZ8AgFrKOJrWaXoBGUi6KLrb/+FwdtB/yaorJXcbvtr0ksReecCbCCZ8 5rOyVPqj2+r9vpuf+pZDIIMvHoEJwhkghfJ+7pNKUrTBHNAy2d23wbI8zxWx0I4tauV0=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=T9ULc9TIG3opxmuyGee3mcp6NGXuFv7wayJE4IT+Pnc=; b=lW47yP/t5/yCTyyW8SLlCS1iZ1 uTGuGc72MRGTGmDOEAixJkduC2YQpyuTWgh84az9axGVDP0vWyHWMAqGv+gkfxlfJ5yo2VzFZyynu 3YrFyONc6AnYeItGy39HkTYjANicH1x/k6lBpKSI+DTALYzxziIk4+b8TrvpszwJoKlI=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1oAoUQ-000846-Ey for openvpn-devel@lists.sourceforge.net; Mon, 11 Jul 2022 08:09:59 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Mon, 11 Jul 2022 10:10:19 +0200 Message-Id: <20220711081019.29511-1-a@unstable.cc> In-Reply-To: <20220706142907.3962-1-a@unstable.cc> References: <20220706142907.3962-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This new API can be used to retrieve the type of a specific interface. It's mostly platform dependant, but right now expected values are "ovpn-dco", "tun" or "tap". Other values are possible too, but they are not of interest to us. Content analysis details: (-0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Headers-End: 1oAoUQ-000846-Ey Subject: [Openvpn-devel] [PATCH v2 pre-05/25] networking: add net_iface_type API X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This new API can be used to retrieve the type of a specific interface. It's mostly platform dependant, but right now expected values are "ovpn-dco", "tun" or "tap". Other values are possible too, but they are not of interest to us. This commit also extends the networking unit-test by using the newly introduced API in conjunction with iface_new and iface_del. The t_next.sh script has been slightly adapted to allow running these tests in standalone (as they don't require any iproute2 counterpart). Signed-off-by: Antonio Quartulli --- Changes from v1: * added unit-test for net_iface_type() * adjusted t_net.sh script so that iface_new/type/del could be executed automatically src/openvpn/networking.h | 14 +++ src/openvpn/networking_iproute2.c | 9 ++ src/openvpn/networking_sitnl.c | 109 +++++++++++++++++++++ tests/t_net.sh | 15 ++- tests/unit_tests/openvpn/test_networking.c | 25 +++-- 5 files changed, 163 insertions(+), 9 deletions(-) diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h index 79963756..cf6d39ac 100644 --- a/src/openvpn/networking.h +++ b/src/openvpn/networking.h @@ -23,6 +23,8 @@ #include "syshead.h" +#define IFACE_TYPE_LEN_MAX 64 + struct context; #ifdef ENABLE_SITNL @@ -100,6 +102,18 @@ void net_ctx_free(openvpn_net_ctx_t *ctx); int net_iface_new(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface, const char *type, void *arg); +/** + * Retrieve the interface type + * + * @param ctx the implementation specific context + * @param iface interface to query + * @param type buffer where the type will be stored + * + * @return 0 on success, a negative error code otherwise + */ +int net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, + char type[IFACE_TYPE_LEN_MAX]); + /** * Remove an interface * diff --git a/src/openvpn/networking_iproute2.c b/src/openvpn/networking_iproute2.c index 4b220576..3062c1da 100644 --- a/src/openvpn/networking_iproute2.c +++ b/src/openvpn/networking_iproute2.c @@ -78,6 +78,15 @@ net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type, return 0; } +int +net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, + char type[IFACE_TYPE_LEN_MAX]) +{ + /* not supported by iproute2 */ + msg(M_WARN, "%s: operation not supported by iproute2 backend", __func__); + return -1; +} + 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 0944ad0a..e97db3f7 100644 --- a/src/openvpn/networking_sitnl.c +++ b/src/openvpn/networking_sitnl.c @@ -1366,6 +1366,115 @@ err: return ret; } +static int +sitnl_parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, + int len, unsigned short flags) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + + while (RTA_OK(rta, len)) + { + type = rta->rta_type & ~flags; + + if ((type <= max) && (!tb[type])) + { + tb[type] = rta; + } + + rta = RTA_NEXT(rta, len); + } + + if (len) + { + msg(D_ROUTE, "%s: %d bytes not parsed! (rta_len=%d)", __func__, len, + rta->rta_len); + } + + return 0; +} + +static int +sitnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + return sitnl_parse_rtattr_flags(tb, max, rta, len, 0); +} + +#define sitnl_parse_rtattr_nested(tb, max, rta) \ + (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), \ + NLA_F_NESTED)) + +static int +sitnl_type_save(struct nlmsghdr *n, void *arg) +{ + char *type = arg; + struct ifinfomsg *ifi = NLMSG_DATA(n); + struct rtattr *tb[IFLA_MAX + 1]; + int ret; + + ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); + if (ret < 0) + { + return ret; + } + + if (tb[IFLA_LINKINFO]) + { + struct rtattr *tb_link[IFLA_INFO_MAX + 1]; + + ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, + tb[IFLA_LINKINFO]); + if (ret < 0) + { + return ret; + } + + if (!tb_link[IFLA_INFO_KIND]) + { + return -ENOENT; + } + + strncpynt(type, RTA_DATA(tb_link[IFLA_INFO_KIND]), IFACE_TYPE_LEN_MAX); + } + + return 0; +} + +int +net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, + char type[IFACE_TYPE_LEN_MAX]) +{ + struct sitnl_link_req req = { }; + int ifindex = if_nametoindex(iface); + + if (!ifindex) + { + return errno; + } + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + + req.i.ifi_family = AF_PACKET; + req.i.ifi_index = ifindex; + + memset(type, 0, IFACE_TYPE_LEN_MAX); + + int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type); + if (ret < 0) + { + msg(D_ROUTE, "%s: cannot retrieve iface %s: %s (%d)", __func__, iface, + strerror(-ret), ret); + return ret; + } + + msg(D_ROUTE, "%s: type of %s: %s", __func__, iface, type); + + return 0; +} + int net_iface_del(openvpn_net_ctx_t *ctx, const char *iface) { diff --git a/tests/t_net.sh b/tests/t_net.sh index af78152c..bc91f825 100755 --- a/tests/t_net.sh +++ b/tests/t_net.sh @@ -2,7 +2,8 @@ IFACE="ovpn-dummy0" UNIT_TEST="./unit_tests/openvpn/networking_testdriver" -MAX_TEST=${1:-7} +LAST_AUTO_TEST=7 +LAST_TEST=8 srcdir="${srcdir:-.}" top_builddir="${top_builddir:-..}" @@ -128,7 +129,7 @@ else fi fi -for i in $(seq 0 $MAX_TEST); do +for i in $(seq 0 $LAST_AUTO_TEST); do # reload dummy module to cleanup state reload_dummy typeset -a STATE_TEST @@ -168,4 +169,14 @@ done # remove interface for good $RUN_SUDO ip link del $IFACE +for i in $(seq $(($LAST_AUTO_TEST + 1)) ${LAST_TEST}); do + $RUN_SUDO $UNIT_TEST $i + if [ $? -ne 0 ]; then + echo "unit-test $i errored out" + exit 1 + fi + + echo "Test $i: OK" +done + exit 0 diff --git a/tests/unit_tests/openvpn/test_networking.c b/tests/unit_tests/openvpn/test_networking.c index 10ed2cb5..c3baedb4 100644 --- a/tests/unit_tests/openvpn/test_networking.c +++ b/tests/unit_tests/openvpn/test_networking.c @@ -2,6 +2,7 @@ #include "syshead.h" #include "networking.h" +#include static char *iface = "ovpn-dummy0"; @@ -16,14 +17,23 @@ net__iface_up(bool up) static int net__iface_new(const char *name, const char *type) { - printf("CMD: ip link add %s type %s\n", name, type); return net_iface_new(NULL, name, type, NULL); } +static int +net__iface_type(const char *name, const char *type) +{ + char ret_type[IFACE_TYPE_LEN_MAX]; + + assert(net_iface_type(NULL, name, ret_type) == 0); + assert(strcmp(type, ret_type) == 0); + + return 0; +} + static int net__iface_del(const char *name) { - printf("CMD: ip link del %s\n", name); return net_iface_del(NULL, name); } @@ -205,7 +215,7 @@ net__route_v6_add_gw(const char *dst_str, int prefixlen, const char *gw_str, static void usage(char *name) { - printf("Usage: %s <0-9>\n", name); + printf("Usage: %s <0-8>\n", name); } int @@ -257,11 +267,12 @@ main(int argc, char *argv[]) case 7: return net__route_v6_add_gw("2001:cafe:babe::", 48, "2001::2", 600); + /* following tests are standalone and do not print any CMD= */ case 8: - return net__iface_new("dummy0815", "dummy"); - - case 9: - return net__iface_del("dummy0815"); + assert(net__iface_new("dummy0815", "dummy") == 0); + assert(net__iface_type("dummy0815", "dummy") == 0); + assert(net__iface_del("dummy0815") == 0); + return 0; default: printf("invalid test: %d\n", test);