On Tue, Jun 18, 2013 at 1:23 AM, Arne Schwabe <a...@rfc2549.org> wrote: > > Mac OS X 10.7+ natively supports tun devices (called utun). The "standard" > utun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do > not work together). > > When OpenVPN is compiled with utun support it will if no dev-node is given > first try to use utun and if that is not available will try the traditional > tun devices > > Parts of the patches are inspired from Peter Sagerson's > <psag...@ignorare.net> utun patch > Signed-off-by: Arne Schwabe <a...@rfc2549.org>
I am anxious to see utun incorporated into OpenVPN and like the functionality this patch provides. I have several comments, all based on the updated patch in Arne's 2013-06-18 email. (Because I am using an old version of OpenVPN, the line numbers in my files don't correspond to those Arne's patch was based on, so the code/patches I show below are pseudo-diffs from the code as patched by Arne's patch, not diffs from any existing code or diffs from his patch.) First, I propose three minor wording changes: Two changes in doc/openvpn.8: -to select a speficic utun instance. To force using the tun.kext (/dev/tunX) use +to select a specific utun instance. To force using the tun.kext (/dev/tunX) use and -option openvpn will try to first open utun first fallback to tun.kext. +option openvpn will first try to open utun, and fall back to tun.kext. One change in src/openvpn/tun.c - msg (M_INFO, "Openend utun device %s", utunname); + msg (M_INFO, "Opened utun device %s", utunname); -------------------------------- Second, I created an experimental build of Tunnelblick that incorporates this patch into OpenVPN 2.3.2. Because Tunnelblick is built in OS X 10.6.8 with Xcode 3.2.2 with the 10.6 SDK (to support PPC and OS X 10.4 - 10.9), it doesn't have /net/if_utun.h, so it doesn't set HAVE_NET_IF_UTUN_H. That combination (TARGET_DARWIN is set, but not HAVE_NET_IF_UTUN_H) generates errors that require some changes: The "}" at the end of open_tun() needs to be conditionalized (Here is the entire routine to clarify why): open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { #ifdef HAVE_NET_IF_UTUN_H /* If dev_node does not start start with utun assume regular tun/tap */ if ((!dev_node && strcmp (dev, "tun")==0) || (dev_node && (strstr (dev_node, "utun") == dev_node))) { /* Try utun first and fall back to normal tun if utun fails * and dev_node is not specified */ open_darwin_utun(dev, dev_type, dev_node, tt); /* No explicit utun and utun failed, try the generic way) */ if (!dev_node && !tt->is_utun) { msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); open_tun_generic (dev, dev_type, NULL, true, true, tt); } } else { #endif /* Use plain dev-node tun to select /dev/tun style * Unset dev_node variable prior to passing to open_tun_generic to * let open_tun_generic pick the first available tun device */ if (dev_node && strcmp (dev_node, "tun")==0) dev_node=NULL; open_tun_generic (dev, dev_type, dev_node, true, true, tt); +#ifdef HAVE_NET_IF_UTUN_H } +#endif } (Or, if you want, you can move the existing #endif up one line instead.) The changes to write_tun and read_tun need to be conditioned on HAVE_NET_IF_UTUN_H being defined: int write_tun (struct tuntap* tt, uint8_t *buf, int len) { +#ifdef HAVE_NET_IF_UTUN_H if (tt->is_utun) return write_tun_header (tt, buf, len); else +#endif return write (tt->fd, buf, len); } int read_tun (struct tuntap* tt, uint8_t *buf, int len) { +#ifdef HAVE_NET_IF_UTUN_H if (tt->is_utun) return read_tun_header (tt, buf, len); else +#endif return read (tt->fd, buf, len); } The resulting binary works on 10.5.8, 10.6.8, and 10.7.5. (Of course, it uses tun, not utun.) -------------------------------- I removed all the the references to HAVE_NET_IF_UTUN_H (so the utun code is compiled even though it is not it is available in the SDK being used) and changed: -#include <net/if_utun.h> +#define UTUN_CONTROL_NAME "com.apple.net.utun_control" +#define UTUN_OPT_IFNAME 2 >>>>> Note: This change should not be put in an OpenVPN patch; it is solely to >>>>> allow me to compile it with the 10.6 SDK. (The values for the UTUN_* variables are taken from 10.7), and it built without problems. -------------------------------- The resulting binary works fine and uses utun on 10.6.8 and 10.7.5. (Interesting that utun isn't in the 10.6 SDK but utun works on 10.6.8. Since it isn't in the SDK, I assume it may be flakey and/or only in some OS X > 10.6.0. If it is flakey in 10.6.8, that's a problem because it will be used by default, but if it is just that it isn't in all of 10.6.*, that should be OK.) On 10.5.8, however, attempting to connect to a server fails with the following messages from the OpenVPN log: 2013-06-19 10:06:28 Opening utun (ioctl(CTLIOCGINFO)): No such file or directory: No such file or directory (errno=2) 2013-06-19 10:06:28 Exiting due to fatal error Someone should build with the patch properly (i.e. not like I did) on 10.7 or 10.8 and test it on 10.5 (and 10.4, ideally) to make sure the fallback really works. (I may be misunderstanding the code, but if "msg (M_ERR..." doesn't return, then that's at least part of the problem.) If fallback doesn't work in 10.4 and 10.5, then my view is that it should be changed so it does work (mostly because Tunnelblick supports 10.4 - 10.8 with a single OpenVPN binary). If OpenVPN doesn't want to support 10.5 or 10.4 to this extent, or if the fallback failure is caused by with the way I worked around not using the 10.7 SDK, I guess I'll just have to deal with it.