[Openvpn-devel,v2,6/7] wintun: set adapter properties via interactive service

Message ID 1573148729-27339-7-git-send-email-lstipakov@gmail.com
State Superseded
Headers show
Series Wintun support | expand

Commit Message

Lev Stipakov Nov. 7, 2019, 6:45 a.m. UTC
From: Lev Stipakov <lev@openvpn.net>

Since Wintun doesn't do DHCP, use interactive service
calls to set up adapter properties.

This also fixes bug in previously unused IPv4 code of
do_address_service():

 - ipv4 address must be in network byte order
 - prefix length cannot be hardcoded /32 but
 must be calculated from netmask

Signed-off-by: Lev Stipakov <lev@openvpn.net>
---
 src/openvpn/route.c |  2 +-
 src/openvpn/route.h |  3 ++-
 src/openvpn/tun.c   | 77 +++++++++++++++++++++++++++++++++++++++++------------
 3 files changed, 63 insertions(+), 19 deletions(-)

Comments

Simon Rozman Nov. 9, 2019, 1:04 a.m. UTC | #1
Hi,

> -----Original Message-----
> From: Lev Stipakov [mailto:lstipakov@gmail.com]
> Sent: Thursday, November 7, 2019 6:45 PM
> To: openvpn-devel@lists.sourceforge.net
> Cc: Lev Stipakov <lev@openvpn.net>
> Subject: [Openvpn-devel] [PATCH v2 6/7] wintun: set adapter properties via
> interactive service
> 
>  static bool
> -do_dns6_service(bool add, const struct tuntap *tt)
> +do_dns_service(bool add, const short family, const struct tuntap *tt)
>  {
>      bool ret = false;
>      ack_message_t ack;
>      struct gc_arena gc = gc_new();
>      HANDLE pipe = tt->options.msg_channel;
> -    int addr_len = add ? tt->options.dns6_len : 0;
> +    int len = family == AF_INET6 ? tt->options.dns6_len :
tt->options.dns_len;
> +    int addr_len = add ? len : 0;
> +    char ip_proto_name[5];
> +
> +    strcpy(ip_proto_name, family == AF_INET6 ? "IPv6" : "IPv4");

const char *ip_proto_name = family == AF_INET6 ? "IPv6" : "IPv4";

... to avoid the strcpy().

The rest LGTM, so...

Acked-by: Simon Rozman <simon@rozman.si>

Best regards,
Simon

Patch

diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 97e90e5..cc6d551 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -3019,7 +3019,7 @@  out:
     return ret;
 }
 
-static bool
+bool
 do_route_ipv4_service(const bool add, const struct route_ipv4 *r, const struct tuntap *tt)
 {
     DWORD if_index = windows_route_find_if_index(r, tt);
diff --git a/src/openvpn/route.h b/src/openvpn/route.h
index 2e68091..27b652c 100644
--- a/src/openvpn/route.h
+++ b/src/openvpn/route.h
@@ -321,7 +321,8 @@  void setenv_routes(struct env_set *es, const struct route_list *rl);
 
 void setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6);
 
-
+bool do_route_ipv4_service(const bool add, const struct route_ipv4 *r,
+                           const struct tuntap *tt);
 
 bool is_special_addr(const char *addr_str);
 
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index ef1415c..c3ea4a8 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -109,8 +109,8 @@  do_address_service(const bool add, const short family, const struct tuntap *tt)
 
     if (addr.family == AF_INET)
     {
-        addr.address.ipv4.s_addr = tt->local;
-        addr.prefix_len = 32;
+        addr.address.ipv4.s_addr = htonl(tt->local);
+        addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask);
     }
     else
     {
@@ -139,13 +139,17 @@  out:
 }
 
 static bool
-do_dns6_service(bool add, const struct tuntap *tt)
+do_dns_service(bool add, const short family, const struct tuntap *tt)
 {
     bool ret = false;
     ack_message_t ack;
     struct gc_arena gc = gc_new();
     HANDLE pipe = tt->options.msg_channel;
-    int addr_len = add ? tt->options.dns6_len : 0;
+    int len = family == AF_INET6 ? tt->options.dns6_len : tt->options.dns_len;
+    int addr_len = add ? len : 0;
+    char ip_proto_name[5];
+
+    strcpy(ip_proto_name, family == AF_INET6 ? "IPv6" : "IPv4");
 
     if (addr_len == 0 && add) /* no addresses to add */
     {
@@ -160,7 +164,7 @@  do_dns6_service(bool add, const struct tuntap *tt)
         },
         .iface = { .index = tt->adapter_index, .name = "" },
         .domains = "",
-        .family = AF_INET6,
+        .family = family,
         .addr_len = addr_len
     };
 
@@ -172,17 +176,24 @@  do_dns6_service(bool add, const struct tuntap *tt)
     {
         addr_len = _countof(dns.addr);
         dns.addr_len = addr_len;
-        msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d",
-            addr_len);
+        msg(M_WARN, "Number of %s DNS addresses sent to service truncated to %d",
+            ip_proto_name, addr_len);
     }
 
     for (int i = 0; i < addr_len; ++i)
     {
-        dns.addr[i].ipv6 = tt->options.dns6[i];
+        if (family == AF_INET6)
+        {
+            dns.addr[i].ipv6 = tt->options.dns6[i];
+        }
+        else
+        {
+            dns.addr[i].ipv4.s_addr = htonl(tt->options.dns[i]);
+        }
     }
 
-    msg(D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service",
-        (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index);
+    msg(D_LOW, "%s %s dns servers on '%s' (if_index = %d) using service",
+        (add ? "Setting" : "Deleting"), ip_proto_name, dns.iface.name, dns.iface.index);
 
     if (!send_msg_iservice(pipe, &dns, sizeof(dns), &ack, "TUN"))
     {
@@ -191,13 +202,13 @@  do_dns6_service(bool add, const struct tuntap *tt)
 
     if (ack.error_number != NO_ERROR)
     {
-        msg(M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]",
-            (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc),
+        msg(M_WARN, "TUN: %s %s dns failed using service: %s [status=%u if_name=%s]",
+            (add ? "adding" : "deleting"), ip_proto_name, strerror_win32(ack.error_number, &gc),
             ack.error_number, dns.iface.name);
         goto out;
     }
 
-    msg(M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted"));
+    msg(M_INFO, "%s dns servers %s using service", ip_proto_name, (add ? "set" : "deleted"));
     ret = true;
 
 out:
@@ -830,7 +841,7 @@  init_tun_post(struct tuntap *tt,
  * an extra call to "route add..."
  * -> helper function to simplify code below
  */
-void
+static void
 add_route_connected_v6_net(struct tuntap *tt,
                            const struct env_set *es)
 {
@@ -862,6 +873,21 @@  delete_route_connected_v6_net(struct tuntap *tt,
 }
 #endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */
 
+#if defined(_WIN32)
+void
+do_route_ipv4_service_tun(bool add, const struct tuntap *tt)
+{
+    struct route_ipv4 r4;
+    CLEAR(r4);
+    r4.network = tt->local & tt->remote_netmask;
+    r4.netmask = tt->remote_netmask;
+    r4.gateway = tt->local;
+    r4.metric = 0;                     /* connected route */
+    r4.flags = RT_DEFINED | RT_METRIC_DEFINED;
+    do_route_ipv4_service(add, &r4, tt);
+}
+#endif
+
 #if defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)  \
     || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
 /* we can't use true subnet mode on tun on all platforms, as that
@@ -1018,7 +1044,7 @@  do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu,
     else if (tt->options.msg_channel)
     {
         do_address_service(true, AF_INET6, tt);
-        do_dns6_service(true, tt);
+        do_dns_service(true, AF_INET6, tt);
     }
     else
     {
@@ -1400,8 +1426,16 @@  do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
     {
         ASSERT(ifname != NULL);
 
-        switch (tt->options.ip_win32_type)
+        if (tt->options.msg_channel && tt->wintun)
+        {
+            do_address_service(true, AF_INET, tt);
+            do_route_ipv4_service_tun(true, tt);
+            do_dns_service(true, AF_INET, tt);
+        }
+        else
         {
+            switch (tt->options.ip_win32_type)
+            {
             case IPW32_SET_MANUAL:
                 msg(M_INFO,
                     "******** NOTE:  Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)",
@@ -1414,6 +1448,7 @@  do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
                                tt->adapter_netmask, NI_IP_NETMASK|NI_OPTIONS);
 
                 break;
+            }
         }
     }
 
@@ -6140,6 +6175,7 @@  open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
     }
 
     /* possibly use IP Helper API to set IP address on adapter */
+    if (!tt->wintun)
     {
         const DWORD index = tt->adapter_index;
 
@@ -6350,7 +6386,7 @@  close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
             do_address_service(false, AF_INET6, tt);
             if (tt->options.dns6_len > 0)
             {
-                do_dns6_service(false, tt);
+                do_dns_service(false, AF_INET6, tt);
             }
         }
         else
@@ -6387,6 +6423,13 @@  close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
         }
     }
 #if 1
+    if (tt->wintun && tt->options.msg_channel)
+    {
+        do_route_ipv4_service_tun(false, tt);
+        do_address_service(false, AF_INET, tt);
+        do_dns_service(false, AF_INET, tt);
+    }
+    else
     if (tt->ipapi_context_defined)
     {
         DWORD status;