]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
networking: add networking API net_addr_ll_set() and use it on Linux
authorAntonio Quartulli <a@unstable.cc>
Fri, 3 Sep 2021 16:11:12 +0000 (18:11 +0200)
committerGert Doering <gert@greenie.muc.de>
Wed, 29 Sep 2021 17:31:37 +0000 (19:31 +0200)
When running in TAP mode we may need to set the LL address of the
interface, if requested by the user.

This operation was overlooked when implementing the networking API and
it still relies on iproute/net-tools being installed.

Basically this means that when compiling OpenVPN on a system without
iproute2/net-tools and the user uses the "lladdr" config directive,
OpenVPN will fail to se the LL address of the interface.

With this patch a new API is introduced, it is implemented for both
SITNL and iproute2 backends, and called on Linux (this is a combination
of three patches in master).

Reported-by: Jan Hugo Prins <jprins@betterbe.com>
Signed-off-by: Antonio Quartulli <a@unstable.cc>
Tested-by: Jan Hugo Prins <jprins@betterbe.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20210903161113.30498-1-a@unstable.cc>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg22792.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit 98f524cbd58d24d09dee26160d7386d710c3564f)
(cherry picked from commit cb5d29461e6e734a2250b984b8423d39f7b9ddaa)
(cherry picked from commit 7205cdd8508be0ec9a83ea2e012e2a495157cad0)

src/openvpn/init.c
src/openvpn/lladdr.c
src/openvpn/lladdr.h
src/openvpn/misc.h
src/openvpn/networking.h
src/openvpn/networking_iproute2.c
src/openvpn/networking_sitnl.c

index 5c3a63f3f7ec068a183c5f6916f3cc966ca60229..27c6cac9105c826440ba8febec7a0c99ed4ccc3e 100644 (file)
@@ -1202,7 +1202,7 @@ do_persist_tuntap(const struct options *options, openvpn_net_ctx_t *ctx)
                ctx);
         if (options->persist_mode && options->lladdr)
         {
-            set_lladdr(options->dev, options->lladdr, NULL);
+            set_lladdr(ctx, options->dev, options->lladdr, NULL);
         }
         return true;
 #else  /* ifdef ENABLE_FEATURE_TUN_PERSIST */
@@ -1874,7 +1874,8 @@ do_open_tun(struct context *c)
     /* set the hardware address */
     if (c->options.lladdr)
     {
-        set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
+        set_lladdr(&c->net_ctx, c->c1.tuntap->actual_name, c->options.lladdr,
+                   c->c2.es);
     }
 
     /* do ifconfig */
index 22857eb76f4d175e8dd6b50d918c100ad524de6f..3ddbebb3896e97909c9f66c3e69283587d371574 100644 (file)
 #include "lladdr.h"
 
 int
-set_lladdr(const char *ifname, const char *lladdr,
+set_lladdr(openvpn_net_ctx_t *ctx, const char *ifname, const char *lladdr,
            const struct env_set *es)
 {
-    struct argv argv = argv_new();
     int r;
 
     if (!ifname || !lladdr)
@@ -27,17 +26,13 @@ set_lladdr(const char *ifname, const char *lladdr,
     }
 
 #if defined(TARGET_LINUX)
-#ifdef ENABLE_IPROUTE
-    argv_printf(&argv,
-                "%s link set addr %s dev %s",
-                iproute_path, lladdr, ifname);
-#else
-    argv_printf(&argv,
-                "%s %s hw ether %s",
-                IFCONFIG_PATH,
-                ifname, lladdr);
-#endif
-#elif defined(TARGET_SOLARIS)
+    uint8_t addr[ETH_ALEN];
+
+    sscanf(lladdr, MAC_FMT, MAC_SCAN_ARG(addr));
+    r = (net_addr_ll_set(ctx, ifname, addr) == 0);
+#else /* if defined(TARGET_LINUX) */
+    struct argv argv = argv_new();
+#if defined(TARGET_SOLARIS)
     argv_printf(&argv,
                 "%s %s ether %s",
                 IFCONFIG_PATH,
@@ -57,18 +52,19 @@ set_lladdr(const char *ifname, const char *lladdr,
                 "%s %s ether %s",
                 IFCONFIG_PATH,
                 ifname, lladdr);
-#else  /* if defined(TARGET_LINUX) */
+#else  /* if defined(TARGET_SOLARIS) */
     msg(M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system.");
     return -1;
-#endif /* if defined(TARGET_LINUX) */
-
+#endif /* if defined(TARGET_SOLARIS) */
     argv_msg(M_INFO, &argv);
     r = openvpn_execve_check(&argv, es, M_WARN, "ERROR: Unable to set link layer address.");
+    argv_free(&argv);
+#endif /* if defined(TARGET_LINUX) */
+
     if (r)
     {
         msg(M_INFO, "TUN/TAP link layer address set to %s", lladdr);
     }
 
-    argv_free(&argv);
     return r;
 }
index f6ea2b1227ce70b98060928a515f60a53c435649..0c8b41649c461ed8b29dfe2a129f9b8e8a7c9cc9 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include "misc.h"
+#include "networking.h"
 
-int set_lladdr(const char *ifname, const char *lladdr,
+int set_lladdr(openvpn_net_ctx_t *ctx, const char *ifname, const char *lladdr,
                const struct env_set *es);
index f195566e927ae330bebc34d1326422adb22c8e67..ef94ca1d8e2eb17564bf57a79f41ec5821093ea4 100644 (file)
@@ -218,4 +218,11 @@ get_num_elements(const char *string, char delimiter);
 struct buffer
 prepend_dir(const char *dir, const char *path, struct gc_arena *gc);
 
+#define _STRINGIFY(S) #S
+#define MAC_FMT _STRINGIFY(%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx)
+#define MAC_PRINT_ARG(_mac) _mac[0], _mac[1], _mac[2],  \
+        _mac[3], _mac[4], _mac[5]
+#define MAC_SCAN_ARG(_mac) &_mac[0], &_mac[1], &_mac[2], \
+        &_mac[3], &_mac[4], &_mac[5]
+
 #endif /* ifndef MISC_H */
index 94f126179ab79ec122d32621c0e92d91642e320c..d43979f03cd9ce718d4fe567bab3f7609692eb60 100644 (file)
@@ -103,6 +103,18 @@ int net_iface_up(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
 int net_iface_mtu_set(openvpn_net_ctx_t *ctx,
                       const openvpn_net_iface_t *iface, uint32_t mtu);
 
+/**
+ * Set the Link Layer (Ethernet) address of the TAP interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to modify
+ * @param addr      the new address to set (expected ETH_ALEN bytes (6))
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                    uint8_t *addr);
+
 /**
  * Add an IPv4 address to an interface
  *
index e4897e3b50d5263c8776ab6543ecaf9a99c852b5..67b8894bc1ba565cbf9bcce940b113f19ec79609 100644 (file)
@@ -93,6 +93,29 @@ net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
     return 0;
 }
 
+int
+net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                uint8_t *addr)
+{
+    struct argv argv = argv_new();
+    int ret = 0;
+
+    argv_printf(&argv,
+                "%s link set addr " MAC_FMT " dev %s",
+                iproute_path, MAC_PRINT_ARG(addr), iface);
+
+    argv_msg(M_INFO, &argv);
+    if (!openvpn_execve_check(&argv, ctx->es, M_WARN,
+                              "Linux ip link set addr failed"))
+    {
+        ret = -1;
+    }
+
+    argv_free(&argv);
+
+    return ret;
+}
+
 int
 net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
                 const in_addr_t *addr, int prefixlen)
index f0dda7a41d78ca91532c4f8e0e2ca418479d0dc4..8610e1d2a41aeb4d2f7f9759b0d79e891dba234a 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "errlevel.h"
 #include "buffer.h"
+#include "misc.h"
 #include "networking.h"
 
 #include <errno.h>
@@ -723,6 +724,40 @@ err:
     return ret;
 }
 
+int
+net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                uint8_t *addr)
+{
+    struct sitnl_link_req req;
+    int ifindex, ret = -1;
+
+    CLEAR(req);
+
+    ifindex = if_nametoindex(iface);
+    if (ifindex == 0)
+    {
+        msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
+            iface);
+        return -1;
+    }
+
+    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
+    req.n.nlmsg_flags = NLM_F_REQUEST;
+    req.n.nlmsg_type = RTM_NEWLINK;
+
+    req.i.ifi_family = AF_PACKET;
+    req.i.ifi_index = ifindex;
+
+    SITNL_ADDATTR(&req.n, sizeof(req), IFLA_ADDRESS, addr, ETH_ALEN);
+
+    msg(M_INFO, "%s: lladdr " MAC_FMT " for %s", __func__, MAC_PRINT_ARG(addr),
+        iface);
+
+    ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
+err:
+    return ret;
+}
+
 static int
 sitnl_addr_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
                const inet_address_t *local, const inet_address_t *remote,