diff --git a/src/openvpn/basic.h b/src/openvpn/basic.h
index d1075b2..6658008 100644
--- a/src/openvpn/basic.h
+++ b/src/openvpn/basic.h
@@ -33,5 +33,6 @@
 #define CLEAR(x) memset(&(x), 0, sizeof(x))
 
 #define IPV4_NETMASK_HOST 0xffffffffU
+#define IPV4_NETBITS_HOST 32U
 
 #endif
diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index 2d3b359..eaf5abb 100644
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -31,6 +31,7 @@
 #include "proto.h"
 #include "socket.h"
 #include "memdbg.h"
+#include "route.h"
 
 static bool
 add_entry(struct client_nat_option_list *dest,
@@ -60,11 +61,11 @@
         for (i = 0; i < list->n; ++i)
         {
             const struct client_nat_entry *e = &list->entries[i];
-            msg(msglevel, "  CNAT[%d] t=%d %s/%s/%s",
+            msg(msglevel, "  CNAT[%d] t=%d %s/%d %s",
                 i,
                 e->type,
                 print_in_addr_t(e->network, IA_NET_ORDER, &gc),
-                print_in_addr_t(e->netmask, IA_NET_ORDER, &gc),
+                e->netbits,
                 print_in_addr_t(e->foreign_network, IA_NET_ORDER, &gc));
         }
     }
@@ -111,6 +112,7 @@
                               int msglevel)
 {
     struct client_nat_entry e;
+    unsigned int netbits = 0;
     bool ok;
 
     if (!strcmp(type, "snat"))
@@ -127,19 +129,35 @@
         return;
     }
 
-    e.network = getaddr(0, network, 0, &ok, NULL);
+    e.network = getaddr(0, network, &netbits, 0, &ok, NULL);
     if (!ok)
     {
         msg(msglevel, "client-nat: bad network: %s", network);
         return;
     }
-    e.netmask = getaddr(0, netmask, 0, &ok, NULL);
-    if (!ok)
+    if (netmask)
     {
-        msg(msglevel, "client-nat: bad netmask: %s", netmask);
+        const in_addr_t mask = getaddr(0, netmask, NULL, 0, &ok, NULL);
+        const int bits = netmask_to_netbits2(mask);
+
+        if (!ok || bits <= 0)
+        {
+            msg(msglevel, "client-nat: bad netmask: %s", netmask);
+            return;
+        }
+        msg(M_WARN, "client-nat network parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+        e.netbits = bits;
+    }
+    else if (netbits > 0)
+    {
+        e.netbits = netbits;
+    }
+    else
+    {
+        msg(msglevel, "client-nat: netmask or bits must be specified");
         return;
     }
-    e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL);
+    e.foreign_network = getaddr(0, foreign_network, NULL, 0, &ok, NULL);
     if (!ok)
     {
         msg(msglevel, "client-nat: bad foreign network: %s", foreign_network);
@@ -210,6 +228,7 @@
     for (i = 0; i < list->n; ++i)
     {
         const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */
+        const in_addr_t netmask = netbits_to_netmask((int)e->netbits);
         if (e->type ^ direction)
         {
             addr = *(addr_ptr = &h->ip.daddr);
@@ -231,13 +250,13 @@
             to = &e->foreign_network;
         }
 
-        if (((addr & e->netmask) == *from) && !(amask & alog))
+        if (((addr & netmask) == *from) && !(amask & alog))
         {
             /* pre-adjust IP checksum */
             ADD_CHECKSUM_32(accumulate, addr);
 
             /* do NAT transform */
-            addr = (addr & ~e->netmask) | *to;
+            addr = (addr & ~netmask) | *to;
 
             /* post-adjust IP checksum */
             SUB_CHECKSUM_32(accumulate, addr);
diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h
index 94141f5..bebd012 100644
--- a/src/openvpn/clinat.h
+++ b/src/openvpn/clinat.h
@@ -36,7 +36,7 @@
 #define CN_DNAT 1
     int type;
     in_addr_t network;
-    in_addr_t netmask;
+    unsigned int netbits;
     in_addr_t foreign_network;
 };
 
diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c
index bbdbc04..30f3539 100644
--- a/src/openvpn/helper.c
+++ b/src/openvpn/helper.c
@@ -64,22 +64,21 @@
 }
 
 static const char *
-print_opt_route(const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc)
+print_opt_route(const in_addr_t network, const int netbits, struct gc_arena *gc)
 {
     struct buffer out = alloc_buf_gc(128, gc);
     ASSERT(network);
 
-    if (netmask)
-    {
-        buf_printf(&out, "route %s %s",
-                   print_in_addr_t(network, 0, gc),
-                   print_in_addr_t(netmask, 0, gc));
-    }
-    else
+    if (netbits < 0)
     {
         buf_printf(&out, "route %s",
                    print_in_addr_t(network, 0, gc));
     }
+    else
+    {
+        buf_printf(&out, "route %s/%d",
+                   print_in_addr_t(network, 0, gc), netbits);
+    }
 
     return BSTR(&out);
 }
@@ -111,27 +110,28 @@
 }
 
 static void
-helper_add_route(const in_addr_t network, const in_addr_t netmask, struct options *o)
+helper_add_route(const in_addr_t network, const int netbits, struct options *o)
 {
     rol_check_alloc(o);
     add_route_to_option_list(o->routes,
                              print_in_addr_t(network, 0, &o->gc),
-                             print_in_addr_t(netmask, 0, &o->gc),
+                             print_in_addr_t(netbits_to_netmask(netbits), 0, &o->gc),
                              NULL,
                              NULL);
 }
 
 static void
-verify_common_subnet(const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet)
+verify_common_subnet(const char *opt, const in_addr_t a, const in_addr_t b, const unsigned int netbits)
 {
     struct gc_arena gc = gc_new();
-    if ((a & subnet) != (b & subnet))
+    const unsigned int var = 32 - netbits;
+    if ((a >> var) != (b >> var))
     {
-        msg(M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet",
+        msg(M_USAGE, "%s IP addresses %s and %s are not in the same /%d subnet",
             opt,
             print_in_addr_t(a, 0, &gc),
             print_in_addr_t(b, 0, &gc),
-            print_in_addr_t(subnet, 0, &gc));
+            netbits);
     }
     gc_free(&gc);
 }
@@ -268,9 +268,6 @@
 
     if (o->server_defined)
     {
-        int netbits = -2;
-        bool status = false;
-
         if (o->client)
         {
             msg(M_USAGE, "--server and --client cannot be used together");
@@ -296,34 +293,24 @@
             msg(M_USAGE, "--server directive only makes sense with --dev tun or --dev tap");
         }
 
-        status = netmask_to_netbits(o->server_network, o->server_netmask, &netbits);
-        if (!status)
-        {
-            msg(M_USAGE, "--server directive network/netmask combination is invalid");
-        }
-
-        if (netbits < 0)
-        {
-            msg(M_USAGE, "--server directive netmask is invalid");
-        }
-
-        if (netbits < IFCONFIG_POOL_MIN_NETBITS)
+        if (o->server_netbits < IFCONFIG_POOL_MIN_NETBITS)
         {
             msg(M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)",
                 print_netmask(IFCONFIG_POOL_MIN_NETBITS, &gc));
         }
 
+        const in_addr_t server_netmask = netbits_to_netmask((int)o->server_netbits);
         if (dev == DEV_TYPE_TUN)
         {
             int pool_end_reserve = 4;
 
-            if (netbits > 29)
+            if (o->server_netbits > 29)
             {
                 msg(M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower",
                     print_netmask(29, &gc));
             }
 
-            if (netbits == 29)
+            if (o->server_netbits == 29)
             {
                 pool_end_reserve = 0;
             }
@@ -342,14 +329,14 @@
                 {
                     o->ifconfig_pool_defined = true;
                     o->ifconfig_pool_start = o->server_network + 4;
-                    o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve;
+                    o->ifconfig_pool_end = (o->server_network | ~server_netmask) - pool_end_reserve;
                     ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
                 }
 
-                helper_add_route(o->server_network, o->server_netmask, o);
+                helper_add_route(o->server_network, o->server_netbits, o);
                 if (o->enable_c2c)
                 {
-                    push_option(o, print_opt_route(o->server_network, o->server_netmask, &o->gc), M_USAGE);
+                    push_option(o, print_opt_route(o->server_network, o->server_netbits, &o->gc), M_USAGE);
                 }
                 else if (o->topology == TOP_NET30)
                 {
@@ -359,16 +346,16 @@
             else if (o->topology == TOP_SUBNET)
             {
                 o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc);
-                o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc);
+                o->ifconfig_remote_netmask = print_in_addr_t(server_netmask, 0, &o->gc);
 
                 if (!(o->server_flags & SF_NOPOOL))
                 {
                     o->ifconfig_pool_defined = true;
                     o->ifconfig_pool_start = o->server_network + 2;
-                    o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1;
+                    o->ifconfig_pool_end = (o->server_network | ~server_netmask) - 1;
                     ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
                 }
-                o->ifconfig_pool_netmask = o->server_netmask;
+                o->ifconfig_pool_netbits = o->server_netbits;
 
                 push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE);
                 if (!o->route_default_gateway)
@@ -393,7 +380,7 @@
         }
         else if (dev == DEV_TYPE_TAP)
         {
-            if (netbits > 30)
+            if (o->server_netbits > 30)
             {
                 msg(M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower",
                     print_netmask(30, &gc));
@@ -402,16 +389,16 @@
             o->mode = MODE_SERVER;
             o->tls_server = true;
             o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc);
-            o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc);
+            o->ifconfig_remote_netmask = print_in_addr_t(server_netmask, 0, &o->gc);
 
             if (!(o->server_flags & SF_NOPOOL))
             {
                 o->ifconfig_pool_defined = true;
                 o->ifconfig_pool_start = o->server_network + 2;
-                o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1;
+                o->ifconfig_pool_end = (o->server_network | ~server_netmask) - 1;
                 ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
             }
-            o->ifconfig_pool_netmask = o->server_netmask;
+            o->ifconfig_pool_netbits = o->server_netbits;
 
             push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE);
         }
@@ -425,7 +412,7 @@
         {
             o->push_ifconfig_constraint_defined = true;
             o->push_ifconfig_constraint_network = o->server_network;
-            o->push_ifconfig_constraint_netmask = o->server_netmask;
+            o->push_ifconfig_constraint_netbits = o->server_netbits;
         }
     }
 
@@ -478,9 +465,9 @@
 
         if (o->server_bridge_defined)
         {
-            verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask);
-            verify_common_subnet("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask);
-            verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask);
+            verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netbits);
+            verify_common_subnet("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netbits);
+            verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netbits);
         }
 
         o->mode = MODE_SERVER;
@@ -492,7 +479,7 @@
             o->ifconfig_pool_start = o->server_bridge_pool_start;
             o->ifconfig_pool_end = o->server_bridge_pool_end;
             ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end);
-            o->ifconfig_pool_netmask = o->server_bridge_netmask;
+            o->ifconfig_pool_netbits = o->server_bridge_netbits;
             push_option(o, print_opt_route_gateway(o->server_bridge_ip, &o->gc), M_USAGE);
         }
         else if (o->server_bridge_proxy_dhcp && !(o->server_flags & SF_NO_PUSH_ROUTE_GATEWAY))
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index dd56961..7f72f8d 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -115,6 +115,7 @@
             const char *dev_type,
             int tun_mtu,
             const char *ifconfig_local,
+            const int ifconfig_netbits,
             const char *ifconfig_remote,
             const char *context,
             const char *signal_text,
@@ -144,7 +145,14 @@
     }
     if (!ifconfig_remote)
     {
-        ifconfig_remote = "";
+        if (ifconfig_netbits > 0)
+        {
+            ifconfig_remote = print_in_addr_t(netbits_to_netmask(ifconfig_netbits), 0, &gc);
+        }
+        else
+        {
+            ifconfig_remote = "";
+        }
     }
     if (!context)
     {
@@ -1948,7 +1956,8 @@
                     dev_type_string(c->options.dev, c->options.dev_type),
                     c->c2.frame.tun_mtu,
                     print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc),
-                    print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc),
+                    c->c1.tuntap->netbits,
+                    print_in_addr_t(c->c1.tuntap->remote, IA_EMPTY_IF_UNDEF, &gc),
                     "init",
                     NULL,
                     "up",
@@ -1988,7 +1997,8 @@
                         dev_type_string(c->options.dev, c->options.dev_type),
                         c->c2.frame.tun_mtu,
                         print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc),
-                        print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc),
+                        c->c1.tuntap->netbits,
+                        print_in_addr_t(c->c1.tuntap->remote, IA_EMPTY_IF_UNDEF, &gc),
                         "restart",
                         NULL,
                         "up",
@@ -2045,7 +2055,8 @@
     struct gc_arena gc = gc_new();
     const char *tuntap_actual = string_alloc(c->c1.tuntap->actual_name, &gc);
     const in_addr_t local = c->c1.tuntap->local;
-    const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask;
+    const int netbits = c->c1.tuntap->netbits;
+    const in_addr_t remote = c->c1.tuntap->remote;
     unsigned long adapter_index = 0;
 #ifdef _WIN32
     adapter_index = c->c1.tuntap->adapter_index;
@@ -2077,7 +2088,8 @@
                         NULL,
                         c->c2.frame.tun_mtu,
                         print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc),
-                        print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc),
+                        netbits,
+                        print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc),
                         "init",
                         signal_description(c->sig->signal_received,
                                            c->sig->signal_text),
@@ -2107,7 +2119,8 @@
                     NULL,
                     c->c2.frame.tun_mtu,
                     print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc),
-                    print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc),
+                    netbits,
+                    print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc),
                     "init",
                     signal_description(c->sig->signal_received,
                                        c->sig->signal_text),
@@ -2137,7 +2150,8 @@
                         NULL,
                         c->c2.frame.tun_mtu,
                         print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc),
-                        print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc),
+                        netbits,
+                        print_in_addr_t(remote, IA_EMPTY_IF_UNDEF, &gc),
                         "restart",
                         signal_description(c->sig->signal_received,
                                            c->sig->signal_text),
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 05b5a1a..a88ee5f 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -554,7 +554,7 @@
         {
             /* IP:port specified */
             bool status;
-            const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, 0, &status, NULL);
+            const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, NULL, 0, &status, NULL);
             if (status)
             {
                 const int port = atoi(p2);
@@ -2803,6 +2803,7 @@
         "untrusted_ip=",
         "ifconfig_local=",
         "ifconfig_netmask=",
+        "ifconfig_netbits=",
         "daemon_start_time=",
         "daemon_pid=",
         "dev=",
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 0509911..aba1a0f 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -1433,7 +1433,8 @@
     const struct options *o = &c->options;
     if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined)
     {
-        return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network;
+        const unsigned int var = 32 - o->push_ifconfig_constraint_netbits;
+        return (c->c2.push_ifconfig_local >> var) == (o->push_ifconfig_constraint_network >> var);
     }
     else
     {
@@ -1512,10 +1513,10 @@
                 mi->context.c2.push_ifconfig_local = remote;
                 if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET))
                 {
-                    mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask;
+                    mi->context.c2.push_ifconfig_remote_netmask = netbits_to_netmask((int)mi->context.options.ifconfig_pool_netbits);
                     if (!mi->context.c2.push_ifconfig_remote_netmask)
                     {
-                        mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask;
+                        mi->context.c2.push_ifconfig_remote_netmask = netbits_to_netmask((int)mi->context.c1.tuntap->netbits);
                     }
                 }
                 else if (tunnel_type == DEV_TYPE_TUN)
@@ -2425,15 +2426,14 @@
     {
         const char *ifconfig_constraint_network =
             print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc);
-        const char *ifconfig_constraint_netmask =
-            print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc);
 
         /* JYFIXME -- this should cause the connection to fail */
         msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) "
-            "violates tunnel network/netmask constraint (%s/%s)",
+            "violates tunnel network/subnet constraint (%s/%d)",
             multi_instance_string(mi, false, &gc),
             print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc),
-            ifconfig_constraint_network, ifconfig_constraint_netmask);
+            ifconfig_constraint_network,
+            mi->context.options.push_ifconfig_constraint_netbits);
     }
 
     /*
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 649f48b..84e9db4 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -1075,7 +1075,7 @@
 #endif /* ifndef _WIN32 */
 
 static in_addr_t
-get_ip_addr(const char *ip_string, int msglevel, bool *error)
+get_ip_addr(const char *ip_string, unsigned int *netbits, int msglevel, bool *error)
 {
     unsigned int flags = GETADDR_HOST_ORDER;
     bool succeeded = false;
@@ -1086,7 +1086,7 @@
         flags |= GETADDR_FATAL;
     }
 
-    ret = getaddr(flags, ip_string, 0, &succeeded, NULL);
+    ret = getaddr(flags, ip_string, netbits, 0, &succeeded, NULL);
     if (!succeeded && error)
     {
         *error = true;
@@ -1333,7 +1333,7 @@
         if (ip_addr_dotted_quad_safe(parm)) /* FQDN -- IP address only */
         {
             bool error = false;
-            const in_addr_t addr = get_ip_addr(parm, msglevel, &error);
+            const in_addr_t addr = get_ip_addr(parm, NULL, msglevel, &error);
             if (!error)
             {
                 array[(*len)++] = addr;
@@ -1513,12 +1513,10 @@
 {
     struct gc_arena gc = gc_new();
 
-    msg(D_SHOW_PARMS, "  server_network = %s", print_in_addr_t(o->server_network, 0, &gc));
-    msg(D_SHOW_PARMS, "  server_netmask = %s", print_in_addr_t(o->server_netmask, 0, &gc));
+    msg(D_SHOW_PARMS, "  server_network = %s/%d", print_in_addr_t(o->server_network, 0, &gc), o->server_netbits);
     msg(D_SHOW_PARMS, "  server_network_ipv6 = %s", print_in6_addr(o->server_network_ipv6, 0, &gc) );
     SHOW_INT(server_netbits_ipv6);
-    msg(D_SHOW_PARMS, "  server_bridge_ip = %s", print_in_addr_t(o->server_bridge_ip, 0, &gc));
-    msg(D_SHOW_PARMS, "  server_bridge_netmask = %s", print_in_addr_t(o->server_bridge_netmask, 0, &gc));
+    msg(D_SHOW_PARMS, "  server_bridge_ip = %s/%d", print_in_addr_t(o->server_bridge_ip, 0, &gc), o->server_bridge_netbits);
     msg(D_SHOW_PARMS, "  server_bridge_pool_start = %s", print_in_addr_t(o->server_bridge_pool_start, 0, &gc));
     msg(D_SHOW_PARMS, "  server_bridge_pool_end = %s", print_in_addr_t(o->server_bridge_pool_end, 0, &gc));
     if (o->push_list.head)
@@ -1534,9 +1532,8 @@
         }
     }
     SHOW_BOOL(ifconfig_pool_defined);
-    msg(D_SHOW_PARMS, "  ifconfig_pool_start = %s", print_in_addr_t(o->ifconfig_pool_start, 0, &gc));
+    msg(D_SHOW_PARMS, "  ifconfig_pool_start = %s/%d", print_in_addr_t(o->ifconfig_pool_start, 0, &gc), o->ifconfig_pool_netbits);
     msg(D_SHOW_PARMS, "  ifconfig_pool_end = %s", print_in_addr_t(o->ifconfig_pool_end, 0, &gc));
-    msg(D_SHOW_PARMS, "  ifconfig_pool_netmask = %s", print_in_addr_t(o->ifconfig_pool_netmask, 0, &gc));
     SHOW_STR(ifconfig_pool_persist_filename);
     SHOW_INT(ifconfig_pool_persist_refresh_freq);
     SHOW_BOOL(ifconfig_ipv6_pool_defined);
@@ -1597,14 +1594,15 @@
               int msglevel)
 {
     struct iroute *ir;
+    unsigned int netbits = 0;
 
     ALLOC_OBJ_GC(ir, struct iroute, &o->gc);
-    ir->network = getaddr(GETADDR_HOST_ORDER, network_str, 0, NULL, NULL);
-    ir->netbits = 32;           /* host route if no netmask given */
+    ir->network = getaddr(GETADDR_HOST_ORDER, network_str, &netbits, 0, NULL, NULL);
+    ir->netbits = 32;           /* host route if no netmask or netbits given */
 
     if (netmask_str)
     {
-        const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, netmask_str, 0, NULL, NULL);
+        const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, netmask_str, NULL, 0, NULL, NULL);
         ir->netbits = netmask_to_netbits2(netmask);
 
         if (ir->netbits < 0)
@@ -1614,6 +1612,11 @@
                 netmask_str);
             return;
         }
+        msg(M_WARN, "iroute network parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+    }
+    else if (netbits)
+    {
+        ir->netbits = (int)netbits;
     }
 
     ir->next = o->iroutes;
@@ -2631,9 +2634,9 @@
         {
             msg(M_USAGE, "--connect-freq only works with --mode server --proto udp.  Try --max-clients instead.");
         }
-        if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
+        if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netbits > 0)
         {
-            msg(M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
+            msg(M_USAGE, "The netbits parameter to --ifconfig-pool is only valid in --dev tap mode");
         }
         if (options->routes && (options->routes->flags & RG_ENABLE))
         {
@@ -6092,11 +6095,29 @@
         iproute_path = p[1];
     }
 #endif
-    else if (streq(p[0], "ifconfig") && p[1] && p[2] && !p[3])
+    else if (streq(p[0], "ifconfig") && p[1] && !p[3])
     {
+        bool error = false;
+
         VERIFY_PERMISSION(OPT_P_UP);
-        if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe(p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */
+        if (!p[2]) /* p[1] must be in CIDR format */
         {
+            unsigned int netbits = 0;
+            get_ip_addr(p[1], &netbits, msglevel, &error);
+            if (error || !netbits)
+            {
+                msg(msglevel, "ifconfig parm '%s' must be a valid address/bits", p[1]);
+                goto err;
+            }
+            options->ifconfig_local = strtok(p[1], "/");
+            /* convert netbits to netmask to unify the storage as string
+             * representation of in_addr_t variables and simplify parsing */
+            options->ifconfig_remote_netmask = print_in_addr_t(netbits_to_netmask((int)netbits), 0, &options->gc);
+        }
+        else if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe(p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */
+        {
+            /* don't suggest CIDR usage here since we don't know if it's a
+             * remote address or a netmask */
             options->ifconfig_local = p[1];
             options->ifconfig_remote_netmask = p[2];
         }
@@ -6999,35 +7020,62 @@
         VERIFY_PERMISSION(OPT_P_PERSIST_IP);
         options->persist_remote_ip = true;
     }
-    else if (streq(p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5])
+    else if (streq(p[0], "client-nat") && p[1] && p[2] && p[3] && !p[5])
     {
+        size_t i = 1;
+        const char *type = p[i++];
+        const char *network = p[i++];
+        const char *netmask = p[i+1] ? p[i++] : NULL;
+        const char *foreign_network = p[i];
+
         VERIFY_PERMISSION(OPT_P_ROUTE);
         cnol_check_alloc(options);
-        add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel);
+        add_client_nat_to_option_list(options->client_nat, type, network, netmask, foreign_network, msglevel);
     }
     else if (streq(p[0], "route") && p[1] && !p[5])
     {
+        size_t i = 1;
+        char *cidr = strchr(p[i], '/');
+        if (cidr && !no_more_than_n_args(msglevel, p, 4, NM_QUOTE_HINT))
+        {
+            goto err;
+        }
+
         VERIFY_PERMISSION(OPT_P_ROUTE);
         rol_check_alloc(options);
         if (pull_mode)
         {
-            if (!ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */
+
+            const char *network = strtok(p[i++], "/"); /* this modifies p[1] */
+            if (!ip_or_dns_addr_safe(network, options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */
             {
-                msg(msglevel, "route parameter network/IP '%s' must be a valid address", p[1]);
+                msg(msglevel, "route parameter network/IP '%s' must be a valid address or address/bits", p[1]);
                 goto err;
             }
-            if (p[2] && !ip_addr_dotted_quad_safe(p[2])) /* FQDN -- must be IP address */
+            if (!cidr && p[i])
             {
-                msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]);
-                goto err;
+                if (!ip_addr_dotted_quad_safe(p[i++])) /* FQDN -- must be IP address */
+                {
+                    msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]);
+                    goto err;
+                }
             }
-            if (p[3] && !ip_or_dns_addr_safe(p[3], options->allow_pull_fqdn) && !is_special_addr(p[3])) /* FQDN -- may be DNS name */
+            if (p[i] && !ip_or_dns_addr_safe(p[i], options->allow_pull_fqdn) && !is_special_addr(p[i])) /* FQDN -- may be DNS name */
             {
-                msg(msglevel, "route parameter gateway '%s' must be a valid address", p[3]);
+                msg(msglevel, "route parameter gateway '%s' must be a valid address", p[i]);
                 goto err;
             }
         }
-        add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4]);
+
+        if (cidr)
+        {
+            *cidr = (char)('/'); /* restore the original CIDR notation for p[1] */
+            add_route_to_option_list(options->routes, p[1], NULL, p[2], p[3]);
+        }
+        else
+        {
+            add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4]);
+        }
     }
     else if (streq(p[0], "route-ipv6") && p[1] && !p[4])
     {
@@ -7348,33 +7396,57 @@
         VERIFY_PERMISSION(OPT_P_GENERAL);
         options->occ = false;
     }
-    else if (streq(p[0], "server") && p[1] && p[2] && !p[4])
+    else if (streq(p[0], "server") && p[1] && !p[4])
     {
         const int lev = M_WARN;
         bool error = false;
-        in_addr_t network, netmask;
+        in_addr_t network;
+        unsigned int netbits = 0;
+        size_t i = 1;
 
         VERIFY_PERMISSION(OPT_P_GENERAL);
-        network = get_ip_addr(p[1], lev, &error);
-        netmask = get_ip_addr(p[2], lev, &error);
-        if (error || !network || !netmask)
+        network = get_ip_addr(p[i++], &netbits, lev, &error);
+        if (netbits)
+        {
+            if (!no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT))
+            {
+                goto err;
+            }
+        }
+        else
+        {
+            const in_addr_t netmask = get_ip_addr(p[i++], NULL, lev, &error);
+            const int nb = netmask_to_netbits2(netmask);
+            if (netmask && nb > 0)
+            {
+                msg(M_WARN, "server network parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+                netbits = nb;
+            }
+            else
+            {
+                msg(M_USAGE, "--server directive network/netmask combination is invalid");
+                goto err;
+            }
+        }
+
+        if (error || !network || !netbits)
         {
             msg(msglevel, "error parsing --server parameters");
             goto err;
         }
         options->server_defined = true;
         options->server_network = network;
-        options->server_netmask = netmask;
+        options->server_netbits = netbits;
 
-        if (p[3])
+        if (p[i])
         {
-            if (streq(p[3], "nopool"))
+            if (streq(p[i], "nopool"))
             {
                 options->server_flags |= SF_NOPOOL;
             }
             else
             {
-                msg(msglevel, "error parsing --server: %s is not a recognized flag", p[3]);
+                msg(msglevel, "error parsing --server: %s is not a recognized flag", p[i]);
                 goto err;
             }
         }
@@ -7403,25 +7475,43 @@
         options->server_network_ipv6 = network;
         options->server_netbits_ipv6 = netbits;
     }
-    else if (streq(p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5])
+    else if (streq(p[0], "server-bridge") && p[1] && p[2] && p[3] && !p[5])
     {
         const int lev = M_WARN;
         bool error = false;
-        in_addr_t ip, netmask, pool_start, pool_end;
+        in_addr_t ip, pool_start, pool_end;
+        unsigned int netbits = 0;
+        size_t i = 1;
 
         VERIFY_PERMISSION(OPT_P_GENERAL);
-        ip = get_ip_addr(p[1], lev, &error);
-        netmask = get_ip_addr(p[2], lev, &error);
-        pool_start = get_ip_addr(p[3], lev, &error);
-        pool_end = get_ip_addr(p[4], lev, &error);
-        if (error || !ip || !netmask || !pool_start || !pool_end)
+        ip = get_ip_addr(p[i++], &netbits, lev, &error);
+        if (netbits)
+        {
+            if (!no_more_than_n_args(msglevel, p, 4, NM_QUOTE_HINT))
+            {
+                goto err;
+            }
+        }
+        else
+        {
+            const in_addr_t netmask = get_ip_addr(p[i++], NULL, lev, &error);
+            const int nb = netmask_to_netbits2(netmask);
+            if (netmask && nb > 0)
+            {
+                msg(M_WARN, "server-bridge gateway parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+                netbits = nb;
+            }
+        }
+        pool_start = get_ip_addr(p[i++], NULL, lev, &error);
+        pool_end = get_ip_addr(p[i], NULL, lev, &error);
+        if (error || !ip || !netbits || !pool_start || !pool_end)
         {
             msg(msglevel, "error parsing --server-bridge parameters");
             goto err;
         }
         options->server_bridge_defined = true;
         options->server_bridge_ip = ip;
-        options->server_bridge_netmask = netmask;
+        options->server_bridge_netbits = netbits;
         options->server_bridge_pool_start = pool_start;
         options->server_bridge_pool_end = pool_end;
     }
@@ -7456,15 +7546,27 @@
     {
         const int lev = M_WARN;
         bool error = false;
-        in_addr_t start, end, netmask = 0;
+        in_addr_t start, end;
+        unsigned int netbits = 0;
 
         VERIFY_PERMISSION(OPT_P_GENERAL);
-        start = get_ip_addr(p[1], lev, &error);
-        end = get_ip_addr(p[2], lev, &error);
-        if (p[3])
+        start = get_ip_addr(p[1], &netbits, lev, &error);
+        end = get_ip_addr(p[2], NULL, lev, &error);
+        if (!netbits && p[3])
         {
-            netmask = get_ip_addr(p[3], lev, &error);
+            const in_addr_t netmask = get_ip_addr(p[3], NULL, lev, NULL);
+            const int nb = netmask_to_netbits2(netmask);
+            if (netmask && nb >= 0)
+            {
+                msg(M_WARN, "ifconfig-pool start-IP parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+                netbits = nb;
+            }
         }
+        else if (netbits && !no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT))
+        {
+            goto err;
+        }
+
         if (error)
         {
             msg(msglevel, "error parsing --ifconfig-pool parameters");
@@ -7478,10 +7580,7 @@
         options->ifconfig_pool_defined = true;
         options->ifconfig_pool_start = start;
         options->ifconfig_pool_end = end;
-        if (netmask)
-        {
-            options->ifconfig_pool_netmask = netmask;
-        }
+        options->ifconfig_pool_netbits = netbits;
     }
     else if (streq(p[0], "ifconfig-pool-persist") && p[1] && !p[3])
     {
@@ -7802,45 +7901,77 @@
         VERIFY_PERMISSION(OPT_P_INSTANCE);
         option_iroute_ipv6(options, p[1], msglevel);
     }
-    else if (streq(p[0], "ifconfig-push") && p[1] && p[2] && !p[4])
+    else if (streq(p[0], "ifconfig-push") && p[1] && !p[4])
     {
-        in_addr_t local, remote_netmask;
+        in_addr_t local, remote_netmask = 0;
+        unsigned int netbits;
+        size_t i = 1;
 
         VERIFY_PERMISSION(OPT_P_INSTANCE);
-        local = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL);
-        remote_netmask = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[2], 0, NULL, NULL);
+        local = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], &netbits, 0, NULL, NULL);
+        if (netbits) /* convert netbits to netmask */
+        {
+            if (!no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT))
+            {
+                goto err;
+            }
+            remote_netmask = netbits_to_netmask((int)netbits);
+        }
+        else if (p[i])
+        {
+            /* don't suggest CIDR usage here since we don't know if it's a
+             * remote address or a netmask */
+            remote_netmask = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], NULL, 0, NULL, NULL);
+        }
+
         if (local && remote_netmask)
         {
             options->push_ifconfig_defined = true;
             options->push_ifconfig_local = local;
             options->push_ifconfig_remote_netmask = remote_netmask;
-            if (p[3])
+            if (p[i])
             {
-                options->push_ifconfig_local_alias = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL);
+                options->push_ifconfig_local_alias = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i], NULL, 0, NULL, NULL);
             }
         }
         else
         {
-            msg(msglevel, "cannot parse --ifconfig-push addresses");
+            msg(msglevel, "cannot parse --ifconfig-push parameters");
             goto err;
         }
     }
-    else if (streq(p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3])
+    else if (streq(p[0], "ifconfig-push-constraint") && p[1] && !p[3])
     {
-        in_addr_t network, netmask;
+        in_addr_t network;
+        unsigned int netbits = 0;
+        size_t i = 1;
 
         VERIFY_PERMISSION(OPT_P_GENERAL);
-        network = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL);
-        netmask = getaddr(GETADDR_HOST_ORDER, p[2], 0, NULL, NULL);
-        if (network && netmask)
+        network = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[i++], &netbits, 0, NULL, NULL);
+        if (!netbits && p[i])
+        {
+            const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2], NULL, 0, NULL, NULL);
+            const int nb = netmask_to_netbits2(netmask);
+            if (netmask && nb > 0)
+            {
+                netbits = nb;
+                msg(M_WARN, "ifconfig-push-constraint network parameter can also be specified as a CIDR address instead of using the separate netmask parameter");
+            }
+        }
+        else if (netbits && !no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT))
+        {
+            goto err;
+        }
+
+        if (network && netbits)
         {
             options->push_ifconfig_constraint_defined = true;
             options->push_ifconfig_constraint_network = network;
-            options->push_ifconfig_constraint_netmask = netmask;
+            options->push_ifconfig_constraint_netbits = netbits;
         }
         else
         {
-            msg(msglevel, "cannot parse --ifconfig-push-constraint addresses");
+            msg(msglevel, "cannot parse --ifconfig-push-constraint parameters");
             goto err;
         }
     }
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index f608cb8..88de24c 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -450,7 +450,7 @@
     const char *tmp_dir;
     bool server_defined;
     in_addr_t server_network;
-    in_addr_t server_netmask;
+    unsigned int server_netbits;
     bool server_ipv6_defined;                           /* IPv6 */
     struct in6_addr server_network_ipv6;                /* IPv6 */
     unsigned int server_netbits_ipv6;                   /* IPv6 */
@@ -464,7 +464,7 @@
 
     bool server_bridge_defined;
     in_addr_t server_bridge_ip;
-    in_addr_t server_bridge_netmask;
+    unsigned int server_bridge_netbits;
     in_addr_t server_bridge_pool_start;
     in_addr_t server_bridge_pool_end;
 
@@ -472,7 +472,7 @@
     bool ifconfig_pool_defined;
     in_addr_t ifconfig_pool_start;
     in_addr_t ifconfig_pool_end;
-    in_addr_t ifconfig_pool_netmask;
+    unsigned int ifconfig_pool_netbits;
     const char *ifconfig_pool_persist_filename;
     int ifconfig_pool_persist_refresh_freq;
 
@@ -499,7 +499,7 @@
     in_addr_t push_ifconfig_local_alias;
     bool push_ifconfig_constraint_defined;
     in_addr_t push_ifconfig_constraint_network;
-    in_addr_t push_ifconfig_constraint_netmask;
+    unsigned int push_ifconfig_constraint_netbits;
     bool push_ifconfig_ipv4_blocked;                    /* IPv4 */
     bool push_ifconfig_ipv6_defined;                    /* IPv6 */
     struct in6_addr push_ifconfig_ipv6_local;           /* IPv6 */
diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c
index e3c3708..84227b6 100644
--- a/src/openvpn/pool.c
+++ b/src/openvpn/pool.c
@@ -652,8 +652,8 @@
             if (strlen(ip_buf) > 0)
             {
                 bool v4_ok = true;
-                in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, 0, &v4_ok,
-                                         NULL);
+                in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, NULL, 0,
+                                         &v4_ok, NULL);
 
                 if (!v4_ok)
                 {
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 6c06374..b8ab470 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -1136,9 +1136,20 @@
                 if (p[0] && !strcmp(p[0], "route") && !p[3] && o->iroutes)
                 {
                     /* get route parameters */
-                    bool status1, status2;
-                    const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], 0, &status1, NULL);
-                    const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL);
+                    bool status1, status2 = true;
+                    int netbits = -1;
+
+                    /* get netbits from CIDR or convert netmask to netbits */
+                    const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], (unsigned int *)&netbits, 0, &status1, NULL);
+                    if (p[2])
+                    {
+                        const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2], NULL, 0, &status2, NULL);
+                        netbits = netmask_to_netbits2(netmask);
+                    }
+                    if (netbits <= 0)
+                    {
+                        netbits = 32;
+                    }
 
                     /* did route parameters parse correctly? */
                     if (status1 && status2)
@@ -1148,7 +1159,7 @@
                         /* does route match an iroute? */
                         for (ir = o->iroutes; ir != NULL; ir = ir->next)
                         {
-                            if (network == ir->network && netmask == netbits_to_netmask(ir->netbits >= 0 ? ir->netbits : 32))
+                            if (network == ir->network && netbits == (ir->netbits >= 0 ? ir->netbits : 32))
                             {
                                 enable = false;
                                 break;
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 91f2032..b743433 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -189,9 +189,9 @@
 route_string(const struct route_ipv4 *r, struct gc_arena *gc)
 {
     struct buffer out = alloc_buf_gc(256, gc);
-    buf_printf(&out, "ROUTE network %s netmask %s gateway %s",
+    buf_printf(&out, "ROUTE network %s/%d gateway %s",
                print_in_addr_t(r->network, 0, gc),
-               print_in_addr_t(r->netmask, 0, gc),
+               r->netbits,
                print_in_addr_t(r->gateway, 0, gc)
                );
     if (r->flags & RT_METRIC_DEFINED)
@@ -321,11 +321,17 @@
            const struct route_option *ro,
            const struct route_list *rl)
 {
-    const in_addr_t default_netmask = IPV4_NETMASK_HOST;
+    const in_addr_t default_netbits = IPV4_NETBITS_HOST;
     bool status;
     int ret;
     struct in_addr special = {0};
 
+    /* separate address and prefix if present */
+    char *network = strdup(ro->network);
+    const char *cidr = strchr(network, '/');
+    const char *addr = strtok(network, "/");
+    const char *prefix = strtok(NULL, "/");
+
     CLEAR(*r);
     r->option = ro;
 
@@ -355,7 +361,7 @@
     else
     {
         ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL,
-                                  ro->network, NULL, 0, NULL, AF_INET, network_list);
+                                  addr, NULL, 0, NULL, AF_INET, network_list);
     }
 
     status = (ret == 0);
@@ -365,25 +371,41 @@
         goto fail;
     }
 
-    /* netmask */
+    /* netbits */
 
+    r->netbits = default_netbits;
     if (is_route_parm_defined(ro->netmask))
     {
-        r->netmask = getaddr(
+        const in_addr_t netmask = getaddr(
             GETADDR_HOST_ORDER
             | GETADDR_WARN_ON_SIGNAL,
             ro->netmask,
+            NULL,
             0,
             &status,
             NULL);
-        if (!status)
+        const int netbits = netmask_to_netbits2(netmask);
+
+        if (!status || netbits < 0)
         {
             goto fail;
         }
+        msg(M_WARN, "route parameter network/IP can also be specified as a CIDR address instead of using the separate netmask parameter");
+        r->netbits = netbits;
     }
-    else
+    else if (cidr)
     {
-        r->netmask = default_netmask;
+        if (!prefix) /* handle 'aa.bb.cc.dd/' case */
+        {
+            goto fail;
+        }
+        char *endp = NULL;
+        const unsigned long netbits = strtoul(prefix, &endp, 10);
+        if ((*endp != '\0') || (netbits > sizeof(in_addr_t) * 8))
+        {
+            goto fail;
+        }
+        r->netbits = netbits;
     }
 
     /* gateway */
@@ -397,6 +419,7 @@
                 | GETADDR_HOST_ORDER
                 | GETADDR_WARN_ON_SIGNAL,
                 ro->gateway,
+                NULL,
                 0,
                 &status,
                 NULL);
@@ -428,7 +451,7 @@
         if (r->metric < 0)
         {
             msg(M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0",
-                ro->network,
+                addr,
                 ro->metric);
             goto fail;
         }
@@ -442,11 +465,13 @@
 
     r->flags |= RT_DEFINED;
 
+    free(network);
     return true;
 
 fail:
     msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s",
         ro->network);
+    free(network);
     return false;
 }
 
@@ -516,7 +541,7 @@
     struct route_option *ro;
     ALLOC_OBJ_GC(ro, struct route_option, l->gc);
     ro->network = network;
-    ro->netmask = netmask;
+    ro->netmask = netmask; /* NULL if network has CIDR notation */
     ro->gateway = gateway;
     ro->metric = metric;
     ro->next = l->routes;
@@ -582,7 +607,7 @@
         r1->flags = RT_DEFINED;
         r1->gateway = target;
         r1->network = gateway->addr & gateway->netmask;
-        r1->netmask = ~(l2-1);
+        r1->netbits = netmask_to_netbits2(gateway->netmask) + 1;
         r1->next = rl->routes;
         rl->routes = r1;
 
@@ -681,6 +706,7 @@
             | GETADDR_HOST_ORDER
             | GETADDR_WARN_ON_SIGNAL,
             remote_endpoint,
+            NULL,
             0,
             &defined,
             NULL);
@@ -921,7 +947,7 @@
 
 static bool
 add_route3(in_addr_t network,
-           in_addr_t netmask,
+           unsigned int netbits,
            in_addr_t gateway,
            const struct tuntap *tt,
            unsigned int flags,
@@ -933,14 +959,14 @@
     CLEAR(r);
     r.flags = RT_DEFINED;
     r.network = network;
-    r.netmask = netmask;
+    r.netbits = netbits;
     r.gateway = gateway;
     return add_route(&r, tt, flags, rgi, es, ctx);
 }
 
 static void
 del_route3(in_addr_t network,
-           in_addr_t netmask,
+           unsigned int netbits,
            in_addr_t gateway,
            const struct tuntap *tt,
            unsigned int flags,
@@ -952,7 +978,7 @@
     CLEAR(r);
     r.flags = RT_DEFINED|RT_ADDED;
     r.network = network;
-    r.netmask = netmask;
+    r.netbits = netbits;
     r.gateway = gateway;
     delete_route(&r, tt, flags, rgi, es, ctx);
 }
@@ -971,7 +997,7 @@
     {
         if (rb->bypass[i])
         {
-            ret = add_route3(rb->bypass[i], IPV4_NETMASK_HOST, gateway, tt,
+            ret = add_route3(rb->bypass[i], IPV4_NETBITS_HOST, gateway, tt,
                              flags | ROUTE_REF_GW, rgi, es, ctx) && ret;
         }
     }
@@ -993,7 +1019,7 @@
         if (rb->bypass[i])
         {
             del_route3(rb->bypass[i],
-                       IPV4_NETMASK_HOST,
+                       IPV4_NETBITS_HOST,
                        gateway,
                        tt,
                        flags | ROUTE_REF_GW,
@@ -1057,7 +1083,7 @@
                 if ((rl->spec.flags & RTSA_REMOTE_HOST)
                     && rl->spec.remote_host != IPV4_INVALID_ADDR)
                 {
-                    ret = add_route3(rl->spec.remote_host, IPV4_NETMASK_HOST,
+                    ret = add_route3(rl->spec.remote_host, IPV4_NETBITS_HOST,
                                      rl->rgi.gateway.addr, tt, flags | ROUTE_REF_GW,
                                      &rl->rgi, es, ctx);
                     rl->iflags |= RL_DID_LOCAL;
@@ -1078,11 +1104,11 @@
                 if (rl->flags & RG_DEF1)
                 {
                     /* add new default route (1st component) */
-                    ret = add_route3(0x00000000, 0x80000000, rl->spec.remote_endpoint,
+                    ret = add_route3(0x00000000, 1, rl->spec.remote_endpoint,
                                      tt, flags, &rl->rgi, es, ctx) && ret;
 
                     /* add new default route (2nd component) */
-                    ret = add_route3(0x80000000, 0x80000000, rl->spec.remote_endpoint,
+                    ret = add_route3(0x80000000, 1, rl->spec.remote_endpoint,
                                      tt, flags, &rl->rgi, es, ctx) && ret;
                 }
                 else
@@ -1120,7 +1146,7 @@
         if (rl->iflags & RL_DID_LOCAL)
         {
             del_route3(rl->spec.remote_host,
-                       IPV4_NETMASK_HOST,
+                       IPV4_NETBITS_HOST,
                        rl->rgi.gateway.addr,
                        tt,
                        flags | ROUTE_REF_GW,
@@ -1140,7 +1166,7 @@
             {
                 /* delete default route (1st component) */
                 del_route3(0x00000000,
-                           0x80000000,
+                           1,
                            rl->spec.remote_endpoint,
                            tt,
                            flags,
@@ -1150,7 +1176,7 @@
 
                 /* delete default route (2nd component) */
                 del_route3(0x80000000,
-                           0x80000000,
+                           1,
                            rl->spec.remote_endpoint,
                            tt,
                            flags,
@@ -1215,7 +1241,7 @@
 
         for (r = rl->routes; r; r = r->next)
         {
-            check_subnet_conflict(r->network, r->netmask, "route");
+            check_subnet_conflict(r->network, netbits_to_netmask((int)r->netbits), "route");
             if (flags & ROUTE_DELETE_FIRST)
             {
                 delete_route(r, tt, flags, &rl->rgi, es, ctx);
@@ -1432,14 +1458,18 @@
     if (r->flags & RT_DEFINED)
     {
         setenv_route_addr(es, "network", r->network, i);
-        setenv_route_addr(es, "netmask", r->netmask, i);
+        setenv_route_addr(es, "netmask", netbits_to_netmask(r->netbits), i);
         setenv_route_addr(es, "gateway", r->gateway, i);
 
+        struct buffer name1 = alloc_buf_gc(256, &gc);
+        buf_printf(&name1, "route_netbits_%d", i);
+        setenv_int(es, BSTR(&name1), (int)r->netbits);
+
         if (r->flags & RT_METRIC_DEFINED)
         {
-            struct buffer name = alloc_buf_gc(256, &gc);
-            buf_printf(&name, "route_metric_%d", i);
-            setenv_int(es, BSTR(&name), r->metric);
+            struct buffer name2 = alloc_buf_gc(256, &gc);
+            buf_printf(&name2, "route_metric_%d", i);
+            setenv_int(es, BSTR(&name2), r->metric);
         }
     }
     gc_free(&gc);
@@ -1519,7 +1549,7 @@
 
 static int
 local_route(in_addr_t network,
-            in_addr_t netmask,
+            unsigned int netbits,
             in_addr_t gateway,
             const struct route_gateway_info *rgi)
 {
@@ -1528,7 +1558,7 @@
     if (rgi
         && (rgi->flags & rgi_needed) == rgi_needed
         && gateway == rgi->gateway.addr
-        && netmask == 0xFFFFFFFF)
+        && netbits == IPV4_NETBITS_HOST)
     {
         if (((network ^  rgi->gateway.addr) & rgi->gateway.netmask) == 0)
         {
@@ -1583,12 +1613,12 @@
 #if !defined(TARGET_LINUX)
     const char *network = print_in_addr_t(r->network, 0, &gc);
 #if !defined(TARGET_AIX)
-    const char *netmask = print_in_addr_t(r->netmask, 0, &gc);
+    const char *netmask = print_in_addr_t(netbits_to_netmask((int)r->netbits), 0, &gc);
 #endif
     const char *gateway = print_in_addr_t(r->gateway, 0, &gc);
 #endif
 
-    is_local_route = local_route(r->network, r->netmask, r->gateway, rgi);
+    is_local_route = local_route(r->network, r->netbits, r->gateway, rgi);
     if (is_local_route == LR_ERROR)
     {
         goto done;
@@ -1609,7 +1639,7 @@
     }
 
     status = RTA_SUCCESS;
-    int ret = net_route_v4_add(ctx, &r->network, netmask_to_netbits2(r->netmask),
+    int ret = net_route_v4_add(ctx, &r->network, (int)r->netbits,
                                &r->gateway, iface, 0, metric);
     if (ret == -EEXIST)
     {
@@ -1840,10 +1870,9 @@
 #elif defined(TARGET_AIX)
 
     {
-        int netbits = netmask_to_netbits2(r->netmask);
         argv_printf(&argv, "%s add -net %s/%d %s",
                     ROUTE_PATH,
-                    network, netbits, gateway);
+                    network, r->netbits, gateway);
         argv_msg(D_ROUTE, &argv);
         bool ret = openvpn_execve_check(&argv, es, 0,
                                         "ERROR: AIX route add command failed");
@@ -2176,14 +2205,14 @@
 #if !defined(TARGET_LINUX)
     network = print_in_addr_t(r->network, 0, &gc);
 #if !defined(TARGET_AIX)
-    netmask = print_in_addr_t(r->netmask, 0, &gc);
+    netmask = print_in_addr_t(netbits_to_netmask((int)r->netbits), 0, &gc);
 #endif
 #if !defined(TARGET_ANDROID)
     gateway = print_in_addr_t(r->gateway, 0, &gc);
 #endif
 #endif
 
-    is_local_route = local_route(r->network, r->netmask, r->gateway, rgi);
+    is_local_route = local_route(r->network, r->netbits, r->gateway, rgi);
     if (is_local_route == LR_ERROR)
     {
         goto done;
@@ -2196,7 +2225,7 @@
         metric = r->metric;
     }
 
-    if (net_route_v4_del(ctx, &r->network, netmask_to_netbits2(r->netmask),
+    if (net_route_v4_del(ctx, &r->network, (int)r->netbits,
                          &r->gateway, NULL, 0, metric) < 0)
     {
         msg(M_WARN, "ERROR: Linux route delete command failed");
@@ -2318,10 +2347,9 @@
 #elif defined(TARGET_AIX)
 
     {
-        int netbits = netmask_to_netbits2(r->netmask);
         argv_printf(&argv, "%s delete -net %s/%d %s",
                     ROUTE_PATH,
-                    network, netbits, gateway);
+                    network, r->netbits, gateway);
         argv_msg(D_ROUTE, &argv);
         openvpn_execve_check(&argv, es, 0, "ERROR: AIX route delete command failed");
     }
@@ -2840,13 +2868,14 @@
     int ret = RTA_ERROR;
     DWORD status;
     const DWORD if_index = (adapter_index == TUN_ADAPTER_INDEX_INVALID) ? windows_route_find_if_index(r, tt) : adapter_index;
+    const in_addr_t netmask = netbits_to_netmask((int)r->netbits);
 
     if (if_index != TUN_ADAPTER_INDEX_INVALID)
     {
         MIB_IPFORWARDROW fr;
         CLEAR(fr);
         fr.dwForwardDest = htonl(r->network);
-        fr.dwForwardMask = htonl(r->netmask);
+        fr.dwForwardMask = htonl(netmask);
         fr.dwForwardPolicy = 0;
         fr.dwForwardNextHop = htonl(r->gateway);
         fr.dwForwardIfIndex = if_index;
@@ -2860,11 +2889,11 @@
         fr.dwForwardMetric4 = METRIC_NOT_USED;
         fr.dwForwardMetric5 = METRIC_NOT_USED;
 
-        if ((r->network & r->netmask) != r->network)
+        if ((r->network & netmask) != r->network)
         {
             msg(M_WARN, "Warning: address %s is not a network address in relation to netmask %s",
                 print_in_addr_t(r->network, 0, &gc),
-                print_in_addr_t(r->netmask, 0, &gc));
+                print_in_addr_t(netmask, 0, &gc));
         }
 
         status = CreateIpForwardEntry(&fr);
@@ -2932,6 +2961,7 @@
     bool ret = false;
     DWORD status;
     const DWORD if_index = windows_route_find_if_index(r, tt);
+    const in_addr_t netmask = netbits_to_netmask((int)r->netbits);
 
     if (if_index != TUN_ADAPTER_INDEX_INVALID)
     {
@@ -2939,7 +2969,7 @@
         CLEAR(fr);
 
         fr.dwForwardDest = htonl(r->network);
-        fr.dwForwardMask = htonl(r->netmask);
+        fr.dwForwardMask = htonl(netmask);
         fr.dwForwardPolicy = 0;
         fr.dwForwardNextHop = htonl(r->gateway);
         fr.dwForwardIfIndex = if_index;
@@ -3016,7 +3046,7 @@
         .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1)
     };
 
-    netmask_to_netbits(r->network, r->netmask, &msg.prefix_len);
+    msg.prefix_len = r->netbits;
     if (msg.prefix_len == -1)
     {
         msg.prefix_len = 32;
@@ -3996,7 +4026,7 @@
     while (iplist)
     {
         bool succeed = false;
-        const in_addr_t ip = getaddr(GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL);
+        const in_addr_t ip = getaddr(GETADDR_HOST_ORDER, iplist->IpAddress.String, NULL, 0, &succeed, NULL);
         if (succeed)
         {
             add_host_route_if_nonlocal(rb, ip);
@@ -4096,7 +4126,7 @@
 {
     if (rgi)
     {
-        if (local_route(addr, 0xFFFFFFFF, rgi->gateway.addr, rgi))
+        if (local_route(addr, IPV4_NETBITS_HOST, rgi->gateway.addr, rgi))
         {
             return TLA_LOCAL;
         }
diff --git a/src/openvpn/route.h b/src/openvpn/route.h
index 421e7d2..a117584 100644
--- a/src/openvpn/route.h
+++ b/src/openvpn/route.h
@@ -117,7 +117,7 @@
     unsigned int flags;
     const struct route_option *option;
     in_addr_t network;
-    in_addr_t netmask;
+    unsigned int netbits;
     in_addr_t gateway;
     int metric;
 };
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index 17c5e76..767036f 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -179,6 +179,7 @@
 in_addr_t
 getaddr(unsigned int flags,
         const char *hostname,
+        unsigned int *netbits,
         int resolve_retry_seconds,
         bool *succeeded,
         struct signal_info *sig_info)
@@ -186,7 +187,7 @@
     in_addr_t addr;
     int status;
 
-    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL,
+    status = get_addr_generic(AF_INET, flags, hostname, &addr, netbits,
                               resolve_retry_seconds, sig_info,
                               M_WARN);
     if (status==0)
diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
index 47083ad..f6165b2 100644
--- a/src/openvpn/socket.h
+++ b/src/openvpn/socket.h
@@ -524,6 +524,7 @@
  */
 in_addr_t getaddr(unsigned int flags,
                   const char *hostname,
+                  unsigned int *netbits,
                   int resolve_retry_seconds,
                   bool *succeeded,
                   struct signal_info *sig_info);
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 739e008..92c5e2b 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -113,7 +113,7 @@
     if (addr.family == AF_INET)
     {
         addr.address.ipv4.s_addr = htonl(tt->local);
-        addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask);
+        addr.prefix_len = tt->netbits;
         msg(D_IFCONFIG, "INET address service: %s %s/%d",
             add ? "add" : "remove",
             print_in_addr_t(tt->local, 0, &gc), addr.prefix_len);
@@ -499,17 +499,17 @@
 static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)";
 
 /*
- * If !tun_p2p, make sure ifconfig_remote_netmask looks
- *  like a netmask.
+ * If !tun_p2p, make sure either ifconfig_netbits is
+ * set or ifconfig_remote looks like a netmask.
  *
- * If tun_p2p, make sure ifconfig_remote_netmask looks
+ * If tun_p2p, make sure ifconfig_remote looks
  *  like an IPv4 address.
  */
 static void
-ifconfig_sanity_check(bool tun_p2p, in_addr_t addr)
+ifconfig_sanity_check(bool tun_p2p, in_addr_t addr, int netbits)
 {
     struct gc_arena gc = gc_new();
-    const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000);
+    const bool looks_like_netmask = addr && ((addr & 0xFF000000) == 0xFF000000);
     if (tun_p2p)
     {
         if (looks_like_netmask)
@@ -521,9 +521,11 @@
     }
     else
     {
-        if (!looks_like_netmask)
+        if (netbits < 0 || !looks_like_netmask)
         {
-            msg(M_WARN, "WARNING: Since you are using subnet topology, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s",
+            msg(M_WARN, "WARNING: Since you are using topology subnet, you must either "
+                "provide a valid prefix length in the first argument of --ifconfig (eg. 10.8.0.0/24) "
+                "or a valid netmask as the second argument (eg. 255.255.255.0). %s",
                 ifconfig_warn_how_to_silence);
         }
     }
@@ -539,34 +541,36 @@
                  int type,
                  in_addr_t public,
                  in_addr_t local,
-                 in_addr_t remote_netmask)
+                 in_addr_t remote,
+                 int netbits)
 {
     struct gc_arena gc = gc_new();
 #if 0
-    msg(M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s",
+    msg(M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, netbits=%d, remote=%s",
         type,
         print_in_addr_t(public, 0, &gc),
         print_in_addr_t(local, 0, &gc),
-        print_in_addr_t(remote_netmask, 0, &gc));
+        netbits,
+        print_in_addr_t(remote, 0, &gc));
 #endif
 
     if (public)
     {
         if (type == DEV_TYPE_TUN)
         {
-            const in_addr_t test_netmask = 0xFFFFFF00;
-            const in_addr_t public_net = public &test_netmask;
-            const in_addr_t local_net = local & test_netmask;
-            const in_addr_t remote_net = remote_netmask & test_netmask;
+            const in_addr_t netmask = netbits < 0 ? 0xFFFFFF00 : netbits_to_netmask(netbits);
+            const in_addr_t public_net = public &netmask;
+            const in_addr_t local_net = local & netmask;
+            const in_addr_t remote_net = remote & netmask;
 
-            if (public == local || public == remote_netmask)
+            if (public == local || public == remote)
             {
                 msg(M_WARN,
                     "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s",
                     name,
                     print_in_addr_t(public, 0, &gc),
                     print_in_addr_t(local, 0, &gc),
-                    print_in_addr_t(remote_netmask, 0, &gc),
+                    print_in_addr_t(remote, 0, &gc),
                     ifconfig_warn_how_to_silence);
             }
 
@@ -577,22 +581,23 @@
                     name,
                     print_in_addr_t(public, 0, &gc),
                     print_in_addr_t(local, 0, &gc),
-                    print_in_addr_t(remote_netmask, 0, &gc),
+                    print_in_addr_t(remote ? remote : netmask, 0, &gc),
                     ifconfig_warn_how_to_silence);
             }
         }
         else if (type == DEV_TYPE_TAP)
         {
-            const in_addr_t public_network = public &remote_netmask;
-            const in_addr_t virtual_network = local & remote_netmask;
-            if (public_network == virtual_network)
+            const in_addr_t netmask = netbits_to_netmask(netbits);
+            const in_addr_t public_network = public &netmask;
+            const in_addr_t virtual_network = local & netmask;
+            if (netmask && public_network == virtual_network)
             {
                 msg(M_WARN,
-                    "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s",
+                    "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s/%d] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s",
                     name,
                     print_in_addr_t(public, 0, &gc),
                     print_in_addr_t(local, 0, &gc),
-                    print_in_addr_t(remote_netmask, 0, &gc),
+                    netbits,
                     ifconfig_warn_how_to_silence);
             }
         }
@@ -669,9 +674,10 @@
     {
         if (!is_tun_p2p(tt))
         {
+            const in_addr_t netmask = netbits_to_netmask(tt->netbits);
             buf_printf(&out, "%s %s",
-                       print_in_addr_t(tt->local & tt->remote_netmask, 0, gc),
-                       print_in_addr_t(tt->remote_netmask, 0, gc));
+                       print_in_addr_t(tt->local & netmask, 0, gc),
+                       print_in_addr_t(netmask, 0, gc));
         }
         else if (tt->type == DEV_TYPE_TUN) /* tun p2p topology */
         {
@@ -679,12 +685,12 @@
             if (remote)
             {
                 r = print_in_addr_t(tt->local, 0, gc);
-                l = print_in_addr_t(tt->remote_netmask, 0, gc);
+                l = print_in_addr_t(tt->remote, 0, gc);
             }
             else
             {
                 l = print_in_addr_t(tt->local, 0, gc);
-                r = print_in_addr_t(tt->remote_netmask, 0, gc);
+                r = print_in_addr_t(tt->remote, 0, gc);
             }
             buf_printf(&out, "%s %s", r, l);
         }
@@ -765,7 +771,8 @@
 {
     struct gc_arena gc = gc_new();
     const char *ifconfig_local = print_in_addr_t(tt->local, 0, &gc);
-    const char *ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc);
+    const char *ifconfig_remote = tt->remote ? print_in_addr_t(tt->remote, 0, &gc) : NULL;
+    const char *ifconfig_netmask = tt->netbits >= 0 ? print_in_addr_t(netbits_to_netmask(tt->netbits), 0, &gc) : NULL;
 
     /*
      * Set environmental variables with ifconfig parameters.
@@ -777,11 +784,12 @@
         setenv_str(es, "ifconfig_local", ifconfig_local);
         if (tun)
         {
-            setenv_str(es, "ifconfig_remote", ifconfig_remote_netmask);
+            setenv_str(es, "ifconfig_remote", ifconfig_remote);
         }
         else
         {
-            setenv_str(es, "ifconfig_netmask", ifconfig_remote_netmask);
+            setenv_int(es, "ifconfig_netbits", tt->netbits);
+            setenv_str(es, "ifconfig_netmask", ifconfig_netmask);
         }
     }
 
@@ -837,7 +845,7 @@
         bool tun_p2p = is_tun_p2p(tt);
 
         /*
-         * Convert arguments to binary IPv4 addresses.
+         * Convert arguments to binary IPv4 addresses and netbits.
          */
 
         tt->local = getaddr(
@@ -846,27 +854,48 @@
             | GETADDR_FATAL_ON_SIGNAL
             | GETADDR_FATAL,
             ifconfig_local_parm,
+            NULL,
             0,
             NULL,
             NULL);
 
-        tt->remote_netmask = getaddr(
+        tt->remote = getaddr(
             (tun_p2p ? GETADDR_RESOLVE : 0)
             | GETADDR_HOST_ORDER
             | GETADDR_FATAL_ON_SIGNAL
             | GETADDR_FATAL,
             ifconfig_remote_netmask_parm,
+            NULL,
             0,
             NULL,
             NULL);
 
+        /* in p2p mode discard the netbits otherwise discard the remote */
+        if (!tun_p2p)
+        {
+            if (tt->remote)
+            {
+                tt->netbits = netmask_to_netbits2(tt->remote);
+                tt->remote = 0;
+            }
+            else
+            {
+                msg(M_FATAL, "init_tun: can not figure out the subnet from the remote parameter (%s)", ifconfig_remote_netmask_parm);
+            }
+            tt->remote = 0;
+        }
+        else
+        {
+            tt->netbits = -1;
+        }
+
         /*
          * Look for common errors in --ifconfig parms
          */
         if (strict_warn)
         {
             struct addrinfo *curele;
-            ifconfig_sanity_check(tun_p2p, tt->remote_netmask);
+            ifconfig_sanity_check(tun_p2p, tt->remote, tt->netbits);
 
             /*
              * If local_public or remote_public addresses are defined,
@@ -877,11 +906,13 @@
             {
                 if (curele->ai_family == AF_INET)
                 {
+                    const in_addr_t local = ntohl(((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr);
                     check_addr_clash("local",
                                      tt->type,
-                                     ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr,
+                                     local,
                                      tt->local,
-                                     tt->remote_netmask);
+                                     tt->remote,
+                                     tt->netbits);
                 }
             }
 
@@ -889,17 +920,19 @@
             {
                 if (curele->ai_family == AF_INET)
                 {
+                    const in_addr_t remote = ntohl(((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr);
                     check_addr_clash("remote",
                                      tt->type,
-                                     ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr,
+                                     remote,
                                      tt->local,
-                                     tt->remote_netmask);
+                                     tt->remote,
+                                     tt->netbits);
                 }
             }
 
             if (!tun_p2p)
             {
-                check_subnet_conflict(tt->local, tt->remote_netmask, "TUN/TAP adapter");
+                check_subnet_conflict(tt->local, netbits_to_netmask(tt->netbits), "TUN/TAP adapter");
             }
             else
             {
@@ -914,12 +947,12 @@
          */
         if (tun_p2p)
         {
-            verify_255_255_255_252(tt->local, tt->remote_netmask);
+            verify_255_255_255_252(tt->local, tt->remote);
             tt->adapter_netmask = ~3;
         }
         else
         {
-            tt->adapter_netmask = tt->remote_netmask;
+            tt->adapter_netmask = netbits_to_netmask(tt->netbits);
         }
 #endif
 
@@ -1062,8 +1095,9 @@
 create_arbitrary_remote( struct tuntap *tt )
 {
     in_addr_t remote;
+    const in_addr_t netmask = netbits_to_netmask(tt->netbits);
 
-    remote = (tt->local & tt->remote_netmask) +1;
+    remote = (tt->local & netmask) +1;
 
     if (remote == tt->local)
     {
@@ -1300,7 +1334,11 @@
 
 #if !defined(TARGET_LINUX)
     const char *ifconfig_local = NULL;
-    const char *ifconfig_remote_netmask = NULL;
+#if !defined(_WIN32)
+    const char *ifconfig_remote = NULL;
+#endif
+    const char *ifconfig_netmask = NULL;
+    const in_addr_t netmask = netbits_to_netmask(tt->netbits);
     struct argv argv = argv_new();
     struct gc_arena gc = gc_new();
 
@@ -1308,7 +1346,10 @@
      * Set ifconfig parameters
      */
     ifconfig_local = print_in_addr_t(tt->local, 0, &gc);
-    ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc);
+#if !defined(_WIN32)
+    ifconfig_remote = print_in_addr_t(tt->remote, 0, &gc);
+#endif
+    ifconfig_netmask = print_in_addr_t(netmask, 0, &gc);
 #endif
 
 #if defined(TARGET_LINUX)
@@ -1324,16 +1365,14 @@
 
     if (tun_p2p)
     {
-        if (net_addr_ptp_v4_add(ctx, ifname, &tt->local,
-                                &tt->remote_netmask) < 0)
+        if (net_addr_ptp_v4_add(ctx, ifname, &tt->local, &tt->remote) < 0)
         {
             msg(M_FATAL, "Linux can't add IP to interface %s", ifname);
         }
     }
     else
     {
-        if (net_addr_v4_add(ctx, ifname, &tt->local,
-                            netmask_to_netbits2(tt->remote_netmask)) < 0)
+        if (net_addr_v4_add(ctx, ifname, &tt->local, tt->netbits) < 0)
         {
             msg(M_FATAL, "Linux can't add IP to interface %s", ifname);
         }
@@ -1341,8 +1380,11 @@
 #elif defined(TARGET_ANDROID)
     char out[64];
 
-    snprintf(out, sizeof(out), "%s %s %d %s", ifconfig_local,
-             ifconfig_remote_netmask, tun_mtu, print_topology(tt->topology));
+    snprintf(out, sizeof(out), "%s %s %d %s",
+             ifconfig_local,
+             ifconfig_remote ? ifconfig_remote : ifconfig_netmask,
+             tun_mtu,
+             print_topology(tt->topology));
     management_android_control(management, "IFCONFIG", out);
 
 #elif defined(TARGET_SOLARIS)
@@ -1354,7 +1396,7 @@
     if (tun_p2p)
     {
         argv_printf(&argv, "%s %s %s %s mtu %d up", IFCONFIG_PATH, ifname,
-                    ifconfig_local, ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_local, ifconfig_remote, tun_mtu);
 
         argv_msg(M_INFO, &argv);
         if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-1 failed"))
@@ -1369,13 +1411,13 @@
     {
         argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
                     ifname, ifconfig_local, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_netmask, tun_mtu);
     }
     else /* tap */
     {
         argv_printf(&argv, "%s %s %s netmask %s up",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask);
+                    ifconfig_netmask);
     }
 
     argv_msg(M_INFO, &argv);
@@ -1390,8 +1432,8 @@
         struct route_ipv4 r;
         CLEAR(r);
         r.flags = RT_DEFINED | RT_METRIC_DEFINED;
-        r.network = tt->local & tt->remote_netmask;
-        r.netmask = tt->remote_netmask;
+        r.network = tt->local & netmask;
+        r.netbits = tt->netbits;
         r.gateway = tt->local;
         r.metric = 0;
         add_route(&r, tt, 0, NULL, es, NULL);
@@ -1413,7 +1455,7 @@
         argv_printf(&argv,
                     "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_remote, tun_mtu);
     }
     else if (tt->type == DEV_TYPE_TUN)
     {
@@ -1421,13 +1463,13 @@
         argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up -link0",
                     IFCONFIG_PATH, ifname, ifconfig_local,
                     print_in_addr_t(remote_end, 0, &gc), tun_mtu,
-                    ifconfig_remote_netmask);
+                    ifconfig_netmask);
     }
     else /* tap */
     {
         argv_printf(&argv, "%s %s %s netmask %s mtu %d link0",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_netmask, tun_mtu);
     }
     argv_msg(M_INFO, &argv);
     openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed");
@@ -1438,8 +1480,8 @@
         struct route_ipv4 r;
         CLEAR(r);
         r.flags = RT_DEFINED;
-        r.network = tt->local & tt->remote_netmask;
-        r.netmask = tt->remote_netmask;
+        r.network = tt->local & netmask;
+        r.netbits = tt->netbits;
         r.gateway = remote_end;
         add_route(&r, tt, 0, NULL, es, NULL);
     }
@@ -1451,14 +1493,14 @@
     {
         argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_remote, tun_mtu);
     }
     else if (tt->type == DEV_TYPE_TUN)
     {
         remote_end = create_arbitrary_remote(tt);
         argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH,
                     ifname, ifconfig_local, print_in_addr_t(remote_end, 0, &gc),
-                    tun_mtu, ifconfig_remote_netmask);
+                    tun_mtu, ifconfig_netmask);
     }
     else /* tap */
     {
@@ -1469,7 +1511,7 @@
          */
         argv_printf(&argv, "%s %s %s netmask %s mtu %d",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_netmask, tun_mtu);
     }
     argv_msg(M_INFO, &argv);
     openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed");
@@ -1480,8 +1522,8 @@
         struct route_ipv4 r;
         CLEAR(r);
         r.flags = RT_DEFINED;
-        r.network = tt->local & tt->remote_netmask;
-        r.netmask = tt->remote_netmask;
+        r.network = tt->local & netmask;
+        r.netbits = tt->netbits;
         r.gateway = remote_end;
         add_route(&r, tt, 0, NULL, es, NULL);
     }
@@ -1503,18 +1545,18 @@
     {
         argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_remote, tun_mtu);
     }
     else if (tt->type == DEV_TYPE_TUN)
     {
         argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up",
                     IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_netmask, tun_mtu);
     }
     else /* tap */
     {
         argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
-                    ifname, ifconfig_local, ifconfig_remote_netmask,
+                    ifname, ifconfig_local, ifconfig_netmask,
                     tun_mtu);
     }
 
@@ -1527,8 +1569,8 @@
         struct route_ipv4 r;
         CLEAR(r);
         r.flags = RT_DEFINED;
-        r.network = tt->local & tt->remote_netmask;
-        r.netmask = tt->remote_netmask;
+        r.network = tt->local & netmask;
+        r.netbits = tt->netbits;
         r.gateway = tt->local;
         add_route(&r, tt, 0, NULL, es, NULL);
     }
@@ -1540,13 +1582,12 @@
     {
         argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
                     IFCONFIG_PATH, ifname, ifconfig_local,
-                    ifconfig_remote_netmask, tun_mtu);
+                    ifconfig_remote, tun_mtu);
     }
     else            /* tun with topology subnet and tap mode (always subnet) */
     {
-        int netbits = netmask_to_netbits2(tt->remote_netmask);
         argv_printf(&argv, "%s %s %s/%d mtu %d up", IFCONFIG_PATH,
-                    ifname, ifconfig_local, netbits, tun_mtu );
+                    ifname, ifconfig_local, tt->netbits, tun_mtu );
     }
 
     argv_msg(M_INFO, &argv);
@@ -1565,7 +1606,7 @@
 
         /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */
         argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
-                    ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu);
+                    ifname, ifconfig_local, ifconfig_netmask, tun_mtu);
 
         argv_msg(M_INFO, &argv);
         openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig failed");
@@ -1578,7 +1619,7 @@
         msg(M_INFO,
             "******** NOTE:  Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)",
             ifname, ifconfig_local,
-            ifconfig_remote_netmask);
+            ifconfig_netmask);
     }
     else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
     {
@@ -1660,12 +1701,10 @@
 undo_ifconfig_ipv4(struct tuntap *tt, openvpn_net_ctx_t *ctx)
 {
 #if defined(TARGET_LINUX)
-    int netbits = netmask_to_netbits2(tt->remote_netmask);
-
     if (is_tun_p2p(tt))
     {
         if (net_addr_ptp_v4_del(ctx, tt->actual_name, &tt->local,
-                                &tt->remote_netmask) < 0)
+                                &tt->remote) < 0)
         {
             msg(M_WARN, "Linux can't del IP from iface %s",
                 tt->actual_name);
@@ -1673,7 +1712,7 @@
     }
     else
     {
-        if (net_addr_v4_del(ctx, tt->actual_name, &tt->local, netbits) < 0)
+        if (net_addr_v4_del(ctx, tt->actual_name, &tt->local, tt->netbits) < 0)
         {
             msg(M_WARN, "Linux can't del IP from iface %s",
                 tt->actual_name);
@@ -4683,8 +4722,8 @@
 
             if (ip_str && netmask_str && strlen(ip_str) && strlen(netmask_str))
             {
-                *ip = getaddr(getaddr_flags, ip_str, 0, &succeed1, NULL);
-                *netmask = getaddr(getaddr_flags, netmask_str, 0, &succeed2, NULL);
+                *ip = getaddr(getaddr_flags, ip_str, NULL, 0, &succeed1, NULL);
+                *netmask = getaddr(getaddr_flags, netmask_str, NULL, 0, &succeed2, NULL);
                 ret = (succeed1 == true && succeed2 == true);
             }
         }
@@ -5370,7 +5409,7 @@
             break;
         }
 
-        ip = getaddr(getaddr_flags, ip_str, 0, &succeed, NULL);
+        ip = getaddr(getaddr_flags, ip_str, NULL, 0, &succeed, NULL);
         if (!succeed)
         {
             break;
@@ -6428,11 +6467,12 @@
     if (!tt->did_ifconfig_setup || tt->topology == TOP_SUBNET)
     {
         in_addr_t ep[3];
+        const in_addr_t netmask = netbits_to_netmask(tt->netbits);
         BOOL status;
 
         ep[0] = htonl(tt->local);
-        ep[1] = htonl(tt->local & tt->remote_netmask);
-        ep[2] = htonl(tt->remote_netmask);
+        ep[1] = htonl(tt->local & netmask);
+        ep[2] = htonl(netmask);
 
         status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN,
                                  ep, sizeof(ep),
@@ -6456,7 +6496,7 @@
     {
         in_addr_t ep[2];
         ep[0] = htonl(tt->local);
-        ep[1] = htonl(tt->remote_netmask);
+        ep[1] = htonl(tt->remote);
 
         if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT,
                              ep, sizeof(ep),
@@ -6485,11 +6525,11 @@
     {
         if (tt->topology == TOP_SUBNET)
         {
-            ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0);
+            ep[2] = dhcp_masq_addr(tt->local, netbits_to_netmask(tt->netbits), tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0);
         }
         else
         {
-            ep[2] = htonl(tt->remote_netmask);
+            ep[2] = htonl(tt->remote);
         }
     }
     else
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 33b9552..68aa3b8 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -188,7 +188,8 @@
 
     /* ifconfig parameters */
     in_addr_t local;
-    in_addr_t remote_netmask;
+    in_addr_t remote;
+    int netbits;
 
     struct in6_addr local_ipv6;
     struct in6_addr remote_ipv6;
