Browse code

Add missing pieces to IPv6 route gateway handling.

OpenVPN on Linux (iproute2+ifconfig), FreeBSD and MacOS X (Darwin)
normally points routes directly towards the "tun" interface, obviating
the need for a gateway. For "tap" interfaces, now add gateway spec to
linux route command, and replace "-iface <dev>" with gateway spec (both
together do not work) on FreeBSD and MacOS X.

Also adapt "route delete" appropriately, otherwise route will not be found.

All other platforms already use the gateway address for tun and tap,
because there's no way to install a route "towards an interface" there.

Remove warning about missing IPv6 route gateway handling.

Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: David Sommerseth <davids@redhat.com>
Message-Id: 1339342891-28443-5-git-send-email-gert@greenie.muc.de
URL: http://article.gmane.org/gmane.network.openvpn.devel/6712
Signed-off-by: David Sommerseth <davids@redhat.com>

Gert Doering authored on 2012/06/11 00:41:30
Showing 2 changed files
... ...
@@ -1251,9 +1251,6 @@ do_init_route_ipv6_list (const struct options *options,
1251 1251
   int dev = dev_type_enum (options->dev, options->dev_type);
1252 1252
   int metric = -1;		/* no metric set */
1253 1253
 
1254
-  if (dev != DEV_TYPE_TUN )
1255
-    msg( M_WARN, "IPv6 routes on TAP devices are going to fail on some platforms (need gateway spec)" );	/* TODO-GERT */
1256
-
1257 1254
   gw = options->ifconfig_ipv6_remote;		/* default GW = remote end */
1258 1255
 #if 0					/* not yet done for IPv6 - TODO!*/
1259 1256
   if ( options->route_ipv6_default_gateway )		/* override? */
... ...
@@ -1550,6 +1550,8 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
1550 1550
   bool status = false;
1551 1551
   const char *device = tt->actual_name;
1552 1552
 
1553
+  bool gateway_needed = false;
1554
+
1553 1555
   if (!r6->defined)
1554 1556
     return;
1555 1557
 
... ...
@@ -1574,6 +1576,18 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
1574 1574
    * (not currently done for IPv6)
1575 1575
    */
1576 1576
 
1577
+  /* On "tun" interface, we never set a gateway if the operating system
1578
+   * can do "route to interface" - it does not add value, as the target
1579
+   * dev already fully qualifies the route destination on point-to-point
1580
+   * interfaces.   OTOH, on "tap" interface, we must always set the
1581
+   * gateway unless the route is to be an on-link network
1582
+   */
1583
+  if ( tt->type == DEV_TYPE_TAP &&
1584
+                  !(r6->metric_defined && r6->metric == 0 ) )
1585
+    {
1586
+      gateway_needed = true;
1587
+    }
1588
+
1577 1589
 #if defined(TARGET_LINUX)
1578 1590
 #ifdef ENABLE_IPROUTE
1579 1591
   argv_printf (&argv, "%s -6 route add %s/%d dev %s",
... ...
@@ -1581,6 +1595,8 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
1581 1581
 	      network,
1582 1582
 	      r6->netbits,
1583 1583
 	      device);
1584
+  if (gateway_needed)
1585
+    argv_printf_cat (&argv, "via %s", gateway);
1584 1586
   if (r6->metric_defined && r6->metric > 0 )
1585 1587
     argv_printf_cat (&argv, " metric %d", r6->metric);
1586 1588
 
... ...
@@ -1590,6 +1606,8 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
1590 1590
 	      network,
1591 1591
 	      r6->netbits,
1592 1592
 	      device);
1593
+  if (gateway_needed)
1594
+    argv_printf_cat (&argv, "gw %s", gateway);
1593 1595
   if (r6->metric_defined && r6->metric > 0 )
1594 1596
     argv_printf_cat (&argv, " metric %d", r6->metric);
1595 1597
 #endif  /*ENABLE_IPROUTE*/
... ...
@@ -1652,20 +1670,29 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
1652 1652
 
1653 1653
 #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
1654 1654
 
1655
-  argv_printf (&argv, "%s add -inet6 %s/%d -iface %s",
1655
+  argv_printf (&argv, "%s add -inet6 %s/%d",
1656 1656
 		ROUTE_PATH,
1657 1657
 	        network,
1658
-	        r6->netbits,
1659
-	        device );
1658
+	        r6->netbits);
1659
+
1660
+  if (gateway_needed)
1661
+    argv_printf_cat (&argv, "%s", gateway);
1662
+  else
1663
+    argv_printf_cat (&argv, "-iface %s", device);
1660 1664
 
1661 1665
   argv_msg (D_ROUTE, &argv);
1662 1666
   status = openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route add -inet6 command failed");
1663 1667
 
1664 1668
 #elif defined(TARGET_DARWIN) 
1665 1669
 
1666
-  argv_printf (&argv, "%s add -inet6 %s -prefixlen %d -iface %s",
1670
+  argv_printf (&argv, "%s add -inet6 %s -prefixlen %d",
1667 1671
 		ROUTE_PATH,
1668
-	        network, r6->netbits, device );
1672
+	        network, r6->netbits );
1673
+
1674
+  if (gateway_needed)
1675
+    argv_printf_cat (&argv, "%s", gateway);
1676
+  else
1677
+    argv_printf_cat (&argv, "-iface %s", device);
1669 1678
 
1670 1679
   argv_msg (D_ROUTE, &argv);
1671 1680
   status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed");
... ...
@@ -1865,6 +1892,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
1865 1865
   const char *network;
1866 1866
   const char *gateway;
1867 1867
   const char *device = tt->actual_name;
1868
+  bool gateway_needed = false;
1868 1869
 
1869 1870
   if (!r6->defined)
1870 1871
     return;
... ...
@@ -1884,6 +1912,16 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
1884 1884
 
1885 1885
   msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits );
1886 1886
 
1887
+  /* if we used a gateway on "add route", we also need to specify it on
1888
+   * delete, otherwise some OSes will refuse to delete the route
1889
+   */
1890
+  if ( tt->type == DEV_TYPE_TAP &&
1891
+                  !(r6->metric_defined && r6->metric == 0 ) )
1892
+    {
1893
+      gateway_needed = true;
1894
+    }
1895
+
1896
+
1887 1897
 #if defined(TARGET_LINUX)
1888 1898
 #ifdef ENABLE_IPROUTE
1889 1899
   argv_printf (&argv, "%s -6 route del %s/%d dev %s",
... ...
@@ -1891,12 +1929,18 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
1891 1891
 	      network,
1892 1892
 	      r6->netbits,
1893 1893
 	      device);
1894
+  if (gateway_needed)
1895
+    argv_printf_cat (&argv, "via %s", gateway);
1894 1896
 #else
1895 1897
   argv_printf (&argv, "%s -A inet6 del %s/%d dev %s",
1896 1898
 		ROUTE_PATH,
1897 1899
 	      network,
1898 1900
 	      r6->netbits,
1899 1901
 	      device);
1902
+  if (gateway_needed)
1903
+    argv_printf_cat (&argv, "gw %s", gateway);
1904
+  if (r6->metric_defined && r6->metric > 0 )
1905
+    argv_printf_cat (&argv, " metric %d", r6->metric);
1900 1906
 #endif  /*ENABLE_IPROUTE*/
1901 1907
   argv_msg (D_ROUTE, &argv);
1902 1908
   openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed");
... ...
@@ -1949,23 +1993,32 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
1949 1949
 
1950 1950
 #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
1951 1951
 
1952
-  argv_printf (&argv, "%s delete -inet6 %s/%d -iface %s",
1952
+  argv_printf (&argv, "%s delete -inet6 %s/%d",
1953 1953
 		ROUTE_PATH,
1954 1954
 	        network,
1955
-	        r6->netbits,
1956
-	        device );
1955
+	        r6->netbits );
1956
+
1957
+  if (gateway_needed)
1958
+    argv_printf_cat (&argv, "%s", gateway);
1959
+  else
1960
+    argv_printf_cat (&argv, "-iface %s", device);
1957 1961
 
1958 1962
   argv_msg (D_ROUTE, &argv);
1959 1963
   openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
1960 1964
 
1961 1965
 #elif defined(TARGET_DARWIN) 
1962 1966
 
1963
-  argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d -iface %s",
1967
+  argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d",
1964 1968
 		ROUTE_PATH, 
1965
-		network, r6->netbits, device );
1969
+		network, r6->netbits );
1970
+
1971
+  if (gateway_needed)
1972
+    argv_printf_cat (&argv, "%s", gateway);
1973
+  else
1974
+    argv_printf_cat (&argv, "-iface %s", device);
1966 1975
 
1967 1976
   argv_msg (D_ROUTE, &argv);
1968
-  openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
1977
+  openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route delete -inet6 command failed");
1969 1978
 
1970 1979
 #elif defined(TARGET_OPENBSD)
1971 1980