Skip to contentSkip to conversation

OpenVPN port to AIX

Openvpn-devel In review Gert Doering 2 participants 13 messages Jun 10, 2014 – Jul 7, 2014

lore
Share & tools
lore
#0 lore raw

Hi,

the following four patches port OpenVPN git/master to AIX. It might not be the most asked-for platform in the world, but since it finally grew a tap driver, it can be useful, so here it is :-)

Drawbacks today:
- AIX has no tun driver, so only --dev tap is supported
- IPv4 ICMP packets are never fragmented, so t_client fails for IPv4 ping with 3000 bytes (while IPv6 works!)

gert

#1 lore raw

PATCH 1/4 Recognize AIX, define TARGET_AIX

From: Gert Doering <[email protected]...>

force "have_tap_header=yes", as configure won't like AIX headers otherwise (no tun related headers, just <net/if_tap.h>).

force ROUTE to be "/usr/sbin/route" - not executable by non-root users, so configure testing for executables will not find it

force "ac_cv_header_net_if_h=no", because AIX' <net/if.h> pulls in AIX' <net/route.h>, which #defines ROUTE_H, disabling our "route.h"... (and we don't need <net/if.h> on AIX anyway)

---
 configure.ac |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)
configure.ac +7 -0
index ea35d73..fe278e1 100644
@@ -342,6 +342,13 @@ case "$host" in
 		AC_DEFINE([TARGET_DRAGONFLY], [1], [Are we running on DragonFlyBSD?])
 		AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["D"], [Target prefix])
 		;;
+	*-aix*)
+		AC_DEFINE([TARGET_AIX], [1], [Are we running AIX?])
+		AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["A"], [Target prefix])
+		ROUTE="/usr/sbin/route"
+		have_tap_header="yes"
+		ac_cv_header_net_if_h="no"	# exists, but breaks things
+		;;
 	*)
 		AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["X"], [Target prefix])
 		have_tap_header="yes"
Signature · 1 line
1.6.4
#2 lore raw

PATCH 2/4 Add tap driver initialization and ifconfig for AIX.

From: Gert Doering <[email protected]...>

AIX is special... ifconfig only works if it can add the data to the ODM right away, so setup a local enviromnment set that has "ODMDIR=/etc/objrepos" in it (hard-coded, nobody changes that).

Only --dev tap or --dev tapNN are supported right now. AIX has no tun driver (so tun mode would need to dynamically add/remove ethernet headers to/from AIX).

---
 src/openvpn/tun.c |  170 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 170 insertions(+), 0 deletions(-)
src/openvpn/tun.c +170 -0
index 482f640..25d5473 100644
@@ -1194,6 +1194,43 @@ do_ifconfig (struct tuntap *tt,
 	  openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
 	}
 
+#elif defined(TARGET_AIX)
+      {
+	/* AIX ifconfig will complain if it can't find ODM path in env */
+	struct env_set *aix_es = env_set_create (NULL);
+	env_set_add( aix_es, "ODMDIR=/etc/objrepos" );
+
+	if (tun)
+	  msg(M_FATAL, "no tun support on AIX (canthappen)");
+
+	/* 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,
+			    actual,
+			    ifconfig_local,
+			    ifconfig_remote_netmask,
+			    tun_mtu
+			    );
+
+	argv_msg (M_INFO, &argv);
+	openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig failed");
+	tt->did_ifconfig = true;
+
+	if ( do_ipv6 )
+	  {
+	    argv_printf (&argv,
+				"%s %s inet6 %s/%d",
+				IFCONFIG_PATH,
+				actual,
+				ifconfig_ipv6_local,
+				tt->netbits_ipv6
+				);
+	    argv_msg (M_INFO, &argv);
+	    openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig inet6 failed");
+	  }
+	env_set_destroy (aix_es);
+      }
 #elif defined (WIN32)
       {
 	/*
@@ -2825,6 +2862,139 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
     return read (tt->fd, buf, len);
 }
 
+#elif defined(TARGET_AIX)
+
+void
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+  char tunname[256];
+  char dynamic_name[20];
+  const char *p;
+  struct argv argv;
+
+  if (tt->type == DEV_TYPE_NULL)
+    {
+      open_null (tt);
+      return;
+    }
+
+  if ( tt->type == DEV_TYPE_TUN)
+    {
+      msg(M_FATAL, "no support for 'tun' devices on AIX" );
+    }
+
+  if ( strncmp( dev, "tap", 3 ) != 0 || dev_node )
+    {
+      msg(M_FATAL, "'--dev %s' and/or '--dev-node' not supported on AIX, use '--dev tap0', 'tap1', etc.", dev );
+    }
+
+  if ( strcmp( dev, "tap" ) == 0 )		/* find first free tap dev */
+    {						/* (= no /dev/tapN node) */
+      int i;
+      for (i=0; i<99; i++ )
+	{
+	  openvpn_snprintf (tunname, sizeof (tunname), "/dev/tap%d", i);
+	  if ( access( tunname, F_OK ) < 0 && errno == ENOENT )
+	    { break; }
+	}
+      if ( i >= 99 )
+	msg( M_FATAL, "cannot find unused tap device" );
+
+      openvpn_snprintf( dynamic_name, sizeof(dynamic_name), "tap%d", i );
+      dev = dynamic_name;
+    }
+  else						/* name given, sanity check */
+    {
+      /* ensure that dev name is "tap+<digits>" *only* */
+      p = &dev[3];
+      while( isdigit(*p) ) p++;
+      if ( *p != '\0' )
+	msg( M_FATAL, "TAP device name must be '--dev tapNNNN'" );
+
+      openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev);
+    }
+
+  /* pre-existing device? 
+   */
+  if ( access( tunname, F_OK ) < 0 && errno == ENOENT )
+    {
+
+      /* tunnel device must be created with 'ifconfig tapN create'
+       */
+      struct env_set *es = env_set_create (NULL);
+      argv_init (&argv);
+      argv_printf (&argv, "%s %s create", IFCONFIG_PATH, dev);
+      argv_msg (M_INFO, &argv);
+      env_set_add( es, "ODMDIR=/etc/objrepos" );
+      openvpn_execve_check (&argv, es, S_FATAL, "AIX 'create tun interface' failed");
+      env_set_destroy (es);
+    }
+  else
+    {
+      /* we didn't make it, we're not going to break it */
+      tt->persistent_if = TRUE;
+    }
+
+  if ((tt->fd = open (tunname, O_RDWR)) < 0)
+    {
+      msg (M_ERR, "Cannot open TAP device '%s'", tunname);
+    }
+
+  set_nonblock (tt->fd);
+  set_cloexec (tt->fd); /* don't pass fd to scripts */
+  msg (M_INFO, "TUN/TAP device %s opened", tunname);
+
+  /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */
+  tt->actual_name = string_alloc(dev, NULL);
+}
+
+/* tap devices need to be manually destroyed on AIX
+ */
+void
+close_tun (struct tuntap* tt)
+{
+  struct gc_arena gc = gc_new ();
+  struct argv argv;
+  struct env_set *es = env_set_create (NULL);
+
+  if (!tt) return;
+
+  /* persistent devices need IP address unconfig, others need destroyal
+   */
+  argv_init (&argv);
+
+  if (tt->persistent_if)
+    {
+      argv_printf (&argv, "%s %s 0.0.0.0 down",
+                          IFCONFIG_PATH, tt->actual_name);
+    }
+  else
+    {
+      argv_printf (&argv, "%s %s destroy",
+                          IFCONFIG_PATH, tt->actual_name);
+    }
+
+  close_tun_generic (tt);
+  argv_msg (M_INFO, &argv);
+  env_set_add( es, "ODMDIR=/etc/objrepos" );
+  openvpn_execve_check (&argv, es, 0, "AIX 'destroy tap interface' failed (non-critical)");
+
+  free(tt);
+  env_set_destroy (es);
+}
+
+int
+write_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+    return write (tt->fd, buf, len);
+}
+
+int
+read_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+    return read (tt->fd, buf, len);
+}
+
 #elif defined(WIN32)
 
 int
Signature · 1 line
1.6.4
#3 lore raw

PATCH 3/4 implement adding/deleting routes on AIX, for IPv4 and IPv6

From: Gert Doering <[email protected]...>

AIX only has TAP interfaces, so always use gateway address as next hop, not interface name.

AIX route works much more reliable if passed netbits than netmask - do so (introducing a new helper function netmask_to_netbits2())

---
 src/openvpn/route.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 60 insertions(+), 0 deletions(-)
src/openvpn/route.c +60 -0
index 5531eda..5428e76 100644
@@ -1482,6 +1482,17 @@ add_route (struct route_ipv4 *r,
   argv_msg (D_ROUTE, &argv);
   status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed");
 
+#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);
+  argv_msg (D_ROUTE, &argv);
+  status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+  }
+
 #else
   msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system.  Try putting your routes in a --route-up script");
 #endif
@@ -1701,6 +1712,14 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
   argv_msg (D_ROUTE, &argv);
   status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed");
 
+#elif defined(TARGET_AIX)
+
+  argv_printf (&argv, "%s add -inet6 %s/%d %s",
+		ROUTE_PATH,
+	        network, r6->netbits, gateway);
+  argv_msg (D_ROUTE, &argv);
+  status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+
 #else
   msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-up script");
 #endif
@@ -1859,8 +1878,21 @@ delete_route (struct route_ipv4 *r,
 
   argv_msg (D_ROUTE, &argv);
   openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed");
+
 #elif defined(TARGET_ANDROID)
   msg (M_NONFATAL, "Sorry, deleting routes on Android is not possible. The VpnService API allows routes to be set on connect only.");
+
+#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);
+  argv_msg (D_ROUTE, &argv);
+  openvpn_execve_check (&argv, es, 0, "ERROR: AIX route delete command failed");
+  }
+
 #else
   msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system.  Try putting your routes in a --route-up script");
 #endif
@@ -2031,6 +2063,14 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
   argv_msg (D_ROUTE, &argv);
   openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed");
 
+#elif defined(TARGET_AIX)
+
+  argv_printf (&argv, "%s delete -inet6 %s/%d %s",
+		ROUTE_PATH,
+	        network, r6->netbits, gateway);
+  argv_msg (D_ROUTE, &argv);
+  openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+
 #else
   msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-down script");
 #endif
@@ -2868,6 +2908,26 @@ netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbi
   return false;
 }
 
+/* similar to netmask_to_netbits(), but don't mess with base address
+ * etc., just convert to netbits - non-mappable masks are returned as "-1"
+ */
+int netmask_to_netbits2 (in_addr_t netmask)
+{
+  int i;
+  const int addrlen = sizeof (in_addr_t) * 8;
+
+  for (i = 0; i <= addrlen; ++i)
+    {
+      in_addr_t mask = netbits_to_netmask (i);
+      if (mask == netmask)
+	{
+	  return i;
+	}
+    }
+  return -1;
+}
+
+
 /*
  * get_bypass_addresses() is used by the redirect-gateway bypass-x
  * functions to build a route bypass to selected DHCP/DNS servers,
Signature · 1 line
1.6.4
#4 lore raw

PATCH 4/4 Make t_client.sh work on AIX.

From: Gert Doering <[email protected]...>

Teach it how to run ifconfig/route on AIX to have meaningful results.

---
 tests/t_client.sh.in |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
tests/t_client.sh.in +6 -0
index 52c5ed1..d4f7c4a 100755
@@ -134,6 +134,12 @@ get_ifconfig_route()
 	   @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$6 }'
 	   return
 	   ;;
+	AIX)
+	   echo "-- AIX --"
+	   @IFCONFIG@ -a | egrep "(flags=|inet)"
+	   @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$6 }'
+	   return
+	   ;;
     esac
 
     echo "get_ifconfig_route(): no idea how to get info on your OS.  FAIL." >&2
Signature · 1 line
1.6.4
#5 lore raw

Re: [Openvpn-devel] [PATCH 4/4] Make t_client.sh work on AIX.

Am 10.06.14 16:04, schrieb Gert Doering:

Quoted 4 lines

From: Gert Doering <[email protected]...>

Teach it how to run ifconfig/route on AIX to have meaningful results.

ACK on the basis of "cannot test, but looks sane and does not touch other platforms"

Arne

#6 lore raw

[Openvpn-devel] [PATCH applied] Re: Make t_client.sh work on AIX.

In reply to Gert Doering

Your patch has been applied to the master branch.

commit a637016ea3a6b49e3c792ca335f50eb32a182093

Author: Gert Doering
Date:   Tue Jun 10 16:04:33 2014 +0200
     Make t_client.sh work on AIX.

     Signed-off-by: Gert Doering <[email protected]...>
     Acked-by: Arne Schwabe <[email protected]...>
     Message-Id: <[email protected]...>
     URL: http://article.gmane.org/gmane.network.openvpn.devel/8786
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#7 lore raw

Re: [Openvpn-devel] [PATCH 3/4] implement adding/deleting routes on AIX, for IPv4 and IPv6

In reply to Gert Doering

Am 10.06.14 16:04, schrieb Gert Doering:

Quoted 8 lines

From: Gert Doering <[email protected]...>

AIX only has TAP interfaces, so always use gateway address as next hop, not interface name.

AIX route works much more reliable if passed netbits than netmask - do so (introducing a new helper function netmask_to_netbits2())

ACK on the basis of "cannot test, but looks sane and does not touch other platforms"

Arne

#8 lore raw

[Openvpn-devel] [PATCH applied] Re: implement adding/deleting routes on AIX, for IPv4 and IPv6

In reply to Gert Doering

Your patch has been applied to the master branch.

(A followup patch will have to come, making use of count_netmask_bits(), and drop the netmask_to_netbits2() helper again)

commit b4b92ae5dca218325dfbe16992922716ea83e261

Author: Gert Doering
Date:   Tue Jun 10 16:04:32 2014 +0200
     implement adding/deleting routes on AIX, for IPv4 and IPv6

     Acked-by: Arne Schwabe <[email protected]...>
     Message-Id: <[email protected]...>
     URL: http://article.gmane.org/gmane.network.openvpn.devel/8785
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#9 lore raw

Re: [Openvpn-devel] [PATCH 2/4] Add tap driver initialization and ifconfig for AIX.

In reply to Gert Doering

Am 10.06.14 16:04, schrieb Gert Doering:

Quoted 10 lines

From: Gert Doering <[email protected]...>

AIX is special... ifconfig only works if it can add the data to the ODM right away, so setup a local enviromnment set that has "ODMDIR=/etc/objrepos" in it (hard-coded, nobody changes that).

Only --dev tap or --dev tapNN are supported right now. AIX has no tun driver (so tun mode would need to dynamically add/remove ethernet headers to/from AIX).

ACK on the basis of "cannot test, but looks sane and does not touch other platforms"

Arne

#10 lore raw

[Openvpn-devel] [PATCH applied] Re: Add tap driver initialization and ifconfig for AIX.

In reply to Gert Doering

Your patch has been applied to the master branch.

commit 7e1e7b46701214f7886af6b408d6954a6621be46

Author: Gert Doering
Date:   Tue Jun 10 16:04:31 2014 +0200
     Add tap driver initialization and ifconfig for AIX.

     Signed-off-by: Gert Doering <[email protected]...>
     Acked-by: Arne Schwabe <[email protected]...>
     Message-Id: <[email protected]...>
     URL: http://article.gmane.org/gmane.network.openvpn.devel/8788
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#11 lore raw

Re: [Openvpn-devel] [PATCH 1/4] Recognize AIX, define TARGET_AIX

In reply to Gert Doering

Am 10.06.14 16:04, schrieb Gert Doering:

Quoted 5 lines

From: Gert Doering <[email protected]...>

force "have_tap_header=yes", as configure won't like AIX headers otherwise (no tun related headers, just <net/if_tap.h>).

Quoted 8 lines

force ROUTE to be "/usr/sbin/route" - not executable by non-root users, so configure testing for executables will not find it

force "ac_cv_header_net_if_h=no", because AIX' <net/if.h> pulls in AIX' <net/route.h>, which #defines ROUTE_H, disabling our "route.h"... (and we don't need <net/if.h> on AIX anyway)

ACK on the basis of "cannot test, but looks sane and does not touch other platforms"

Arne

#12 lore raw

[Openvpn-devel] [PATCH applied] Re: Recognize AIX, define TARGET_AIX

In reply to Gert Doering

Your patch has been applied to the master branch.

commit 42f13dc03c12805b994ea67fe77c9cb9dd55c10d

Author: Gert Doering
Date:   Tue Jun 10 16:04:30 2014 +0200
     Recognize AIX, define TARGET_AIX

     Signed-off-by: Gert Doering <[email protected]...>
     Acked-by: Arne Schwabe <[email protected]...>
     Message-Id: <[email protected]...>
     URL: http://article.gmane.org/gmane.network.openvpn.devel/8787
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering