|
From: Arne S. <ar...@rf...> - 2013-03-31 20:43:43
|
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
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
src/openvpn/tun.c | 294 ++++++++++++++++++++++++++++++++++++++++-------------
src/openvpn/tun.h | 5 +-
3 files changed, 231 insertions(+), 70 deletions(-)
diff --git a/configure.ac b/configure.ac
index 7b35e50..5994991 100644
--- a/configure.ac
+++ b/configure.ac
@@ -454,7 +454,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index a361233..089fe59 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -673,7 +673,7 @@ do_ifconfig (struct tuntap *tt,
}
#endif
-
+
#if defined(TARGET_LINUX)
#ifdef ENABLE_IPROUTE
/*
@@ -1248,6 +1248,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -1972,23 +2053,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2055,59 +2119,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2467,10 +2488,141 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd == -1)
+ {
+ msg (M_ERR, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -1;
+ }
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_ERR, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -1;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) == -1)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-type %s' please use 'dev-type utunX'"
+ "to use a specific utun device", dev_node);
+ }
+
+
+
+ memset(&ctlInfo, 0, sizeof(ctlInfo));
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun (%s): %s", "UTUN_CONTROL_NAME too long",
+ strerror (errno));
+
+ }
+
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ if (fd != -1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ sprintf(utunname, "utun%d",utunnum);
+ tt->actual_name = strdup (utunname);
+
+ msg (M_INFO, "Openend utun device %s", utunname);
+
+ tt->fd = fd;
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+#ifdef HAVE_NET_IF_UTUN_H
+ /* If dev_node does not start start with utun assume regular tun/tap */
+ if (dev_node && !(strstr (dev_node, "utun") == dev_node))
+ return open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+
+ /* Otherwise try utun first and fall back to normal tun if utun fails
+ * and dev_node is not specified */
+
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ 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 tun device");
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+ }
+ }
+ else
+#endif
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
}
void
@@ -2503,13 +2655,19 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, len);
+ if (tt->is_utun)
+ return write_tun_header (tt, buf, len);
+ else
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return read (tt->fd, buf, len);
+ if (tt->is_utun)
+ return read_tun_header (tt, buf, len);
+ else
+ return read (tt->fd, buf, len);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index c3fc62e..dc6429c 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -180,7 +180,10 @@ struct tuntap
#ifdef TARGET_SOLARIS
int ip_fd;
#endif
-
+
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Gert D. <ge...@gr...> - 2013-04-01 11:12:44
|
Hi,
On Sun, Mar 31, 2013 at 10:43:29PM +0200, Arne Schwabe 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
I'm not fully sure whether I like this or not, but I can see the necessity
if tun.ko is just not working in certain circumstances.
I'd very much like to hear from "GUI authors" for MacOS X about this,
though - copying Jonathan: what do you think is the way forward here,
and should this go into a soon-to-be-released 2.3.2, or is this "long-term
future" material for 2.4?
gert
--
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany ge...@gr...
fax: +49-89-35655025 ge...@ne...
|
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-01 13:26:55
|
On Mon, Apr 1, 2013 at 7:12 AM, Gert Doering <ge...@gr...> wrote: > Hi, > > On Sun, Mar 31, 2013 at 10:43:29PM +0200, Arne Schwabe 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 The "utun" stuff is new to me; all I can find is the source code for it. Is this one of the "hidden features" of iOS that that OpenVPN for iOS app uses, and that is also in OS X 10.7 and up? Most configuration files I've seen do not include a dev-node option. Does a "dev tun" option in the file imply, for this purpose, "dev-type tun"? If I understand this correctly, a user who updates to 10.7+ will be using utun instead of tun. That may be problematic (I don't know). Wouldn't it be better to use the legacy tun if it exists, and if not, then use the utun? That would be backward-compatible with such configuration files. > > I'm not fully sure whether I like this or not, but I can see the necessity > if tun.ko is just not working in certain circumstances. > > I'd very much like to hear from "GUI authors" for MacOS X about this, > though - copying Jonathan: what do you think is the way forward here, > and should this go into a soon-to-be-released 2.3.2, or is this "long-term > future" material for 2.4? I don't have an opinion about including it in 2.3.2 vs. 2.4 -- I still can't get anything after 2.3alpha1 to build properly for Tunnelblick! I gave up on that several months ago, but last week someone else started working on it and is making progress. > > gert > -- > USENET is *not* the non-clickable part of WWW! > //www.muc.de/~gert/ > Gert Doering - Munich, Germany ge...@gr... > fax: +49-89-35655025 ge...@ne... |
|
From: Arne S. <ar...@rf...> - 2013-04-01 14:29:31
Attachments:
smime.p7s
|
Am 01.04.13 15:26, schrieb Jonathan K. Bullard: > On Mon, Apr 1, 2013 at 7:12 AM, Gert Doering <ge...@gr...> wrote: >> Hi, >> >> On Sun, Mar 31, 2013 at 10:43:29PM +0200, Arne Schwabe 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 > > The "utun" stuff is new to me; all I can find is the source code for > it. Is this one of the "hidden features" of iOS that that OpenVPN for > iOS app uses, and that is also in OS X 10.7 and up? Basically yes. > Most configuration files I've seen do not include a dev-node option. > Does a "dev tun" option in the file imply, for this purpose, "dev-type > tun"? > > If I understand this correctly, a user who updates to 10.7+ will be > using utun instead of tun. That may be problematic (I don't know). > > Wouldn't it be better to use the legacy tun if it exists, and if not, > then use the utun? That would be backward-compatible with such > configuration files. Currently the patch tries to open utun first and if that fails it will try to open tun. If you specify something like dev-node tun17 or dev-node utun23 it will only try to open that specific kind of tun node. Arne |
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-01 14:44:50
|
On Mon, Apr 1, 2013 at 10:29 AM, Arne Schwabe <ar...@rf...> wrote: > > Am 01.04.13 15:26, schrieb Jonathan K. Bullard: > >> On Mon, Apr 1, 2013 at 7:12 AM, Gert Doering <ge...@gr...> wrote: >>> >>> Hi, >>> >>> On Sun, Mar 31, 2013 at 10:43:29PM +0200, Arne Schwabe 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 >> >> >> The "utun" stuff is new to me; all I can find is the source code for >> it. Is this one of the "hidden features" of iOS that that OpenVPN for >> iOS app uses, and that is also in OS X 10.7 and up? > > Basically yes. > >> Most configuration files I've seen do not include a dev-node option. >> Does a "dev tun" option in the file imply, for this purpose, "dev-type >> tun"? >> >> If I understand this correctly, a user who updates to 10.7+ will be >> using utun instead of tun. That may be problematic (I don't know). >> >> Wouldn't it be better to use the legacy tun if it exists, and if not, >> then use the utun? That would be backward-compatible with such >> configuration files. > > > Currently the patch tries to open utun first and if that fails it will try > to open tun. If you specify something like dev-node tun17 or dev-node utun23 > it will only try to open that specific kind of tun node. Yes. The point I was trying to make was that most configuration files that I've seen don't have 'dev-node' options, so they will try utun first and only if that fails will they try try to open tun. So when they update to 10.7+, OpenVPN will start to use utun instead of tun (since it will be available in 10.7+), and that may break backward compatibility if the utun doesn't work exactly the same way that tun works, which I gather from the comment that >>>> The "standard" utun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). If it is the other way around (use tun if it is available and if not, try utun) then anybody who has loaded tun will continue to work with that tun, and anybody who hasn't loaded tun will get utun if it is available. So nothing breaks. It's hard for a GUI like Tunnelblick that doesn't parse the configuration file to detect the situation (no dev-type option) to add a "dev-type tun" to force the use of tun. But if we know that utun works for OpenVPN, then I don't have any problem with the patch. But that utun "is sometimes problematic" makes me worried that this may not be the case. |
|
From: Arne S. <ar...@rf...> - 2013-04-01 15:06:26
Attachments:
smime.p7s
|
>>>>> The "standard" utun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). > If it is the other way around (use tun if it is available and if not, > try utun) then anybody who has loaded tun will continue to work with > that tun, and anybody who hasn't loaded tun will get utun if it is > available. So nothing breaks. > > It's hard for a GUI like Tunnelblick that doesn't parse the > configuration file to detect the situation (no dev-type option) to add > a "dev-type tun" to force the use of tun. > > But if we know that utun works for OpenVPN, then I don't have any > problem with the patch. But that utun "is sometimes problematic" makes > me worried that this may not be the case. The short history behind the patch: I was investing why Tunnelblick was not working on a collegues Macbook and as it turned out that you can have tun.ko loaded or the VmWare Fusion network driver (at least on his Macbook). Otherwise you get errors on loading the module. But I remembered something about the utun stuff, found the example code again and come up with the patch. The setence from the commit should have been: The "standard" tun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). The utun driver not be fully compatbile with behaviour of the standard tun.ko driver but all my tests (IPv6, IPv4) worked so far. For 2.3.x I fine with try utun first or try tun first behaviour but for -master/2.4 I would like to have try utun first so more people actually use utun so we get to know if it is really 100% compatible/working. Arne |
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-01 15:19:29
|
On Mon, Apr 1, 2013 at 11:06 AM, Arne Schwabe <ar...@rf...> wrote: > > >>>>>> The "standard" utun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). >> >> If it is the other way around (use tun if it is available and if not, >> try utun) then anybody who has loaded tun will continue to work with >> that tun, and anybody who hasn't loaded tun will get utun if it is >> available. So nothing breaks. >> >> It's hard for a GUI like Tunnelblick that doesn't parse the >> configuration file to detect the situation (no dev-type option) to add >> a "dev-type tun" to force the use of tun. >> >> But if we know that utun works for OpenVPN, then I don't have any >> problem with the patch. But that utun "is sometimes problematic" makes >> me worried that this may not be the case. > > The short history behind the patch: I was investing why Tunnelblick was not working on a collegues Macbook and as it turned out that you can have tun.ko loaded or the VmWare Fusion network driver (at least on his Macbook). Otherwise you get errors on loading the module. But I remembered something about the utun stuff, found the example code again and come up with the patch. The setence from the commit should have been: > > The "standard" tun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). > > The utun driver not be fully compatbile with behaviour of the standard tun.ko driver but all my tests (IPv6, IPv4) worked so far. For 2.3.x I fine with try utun first or try tun first behaviour but for -master/2.4 I would like to have try utun first so more people actually use utun so we get to know if it is really 100% compatible/working. Thanks; I get it. So it is the "standard" tun driver that is a problem, and the utun driver fixes that problem. In that case, patch is OK with me. By "the 'standard' tun.ko driver", do you mean "tun.kext" from tuntaposx (http://tuntaposx.sourceforge.net), which is what Tunnelblick uses, or are you talking about something else? |
|
From: Arne S. <ar...@rf...> - 2013-04-01 15:31:07
Attachments:
smime.p7s
|
Am 01.04.13 17:18, schrieb Jonathan K. Bullard: > On Mon, Apr 1, 2013 at 11:06 AM, Arne Schwabe <ar...@rf...> wrote: >> >>>>>>> The "standard" utun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). >>> If it is the other way around (use tun if it is available and if not, >>> try utun) then anybody who has loaded tun will continue to work with >>> that tun, and anybody who hasn't loaded tun will get utun if it is >>> available. So nothing breaks. >>> >>> It's hard for a GUI like Tunnelblick that doesn't parse the >>> configuration file to detect the situation (no dev-type option) to add >>> a "dev-type tun" to force the use of tun. >>> >>> But if we know that utun works for OpenVPN, then I don't have any >>> problem with the patch. But that utun "is sometimes problematic" makes >>> me worried that this may not be the case. >> The short history behind the patch: I was investing why Tunnelblick was not working on a collegues Macbook and as it turned out that you can have tun.ko loaded or the VmWare Fusion network driver (at least on his Macbook). Otherwise you get errors on loading the module. But I remembered something about the utun stuff, found the example code again and come up with the patch. The setence from the commit should have been: >> >> The "standard" tun.ko driver is sometimes problematic (e.g. VmWare Fusion 5 and tun.ko do not work together). >> >> The utun driver not be fully compatbile with behaviour of the standard tun.ko driver but all my tests (IPv6, IPv4) worked so far. For 2.3.x I fine with try utun first or try tun first behaviour but for -master/2.4 I would like to have try utun first so more people actually use utun so we get to know if it is really 100% compatible/working. > Thanks; I get it. So it is the "standard" tun driver that is a > problem, and the utun driver fixes that problem. In that case, patch > is OK with me. > > By "the 'standard' tun.ko driver", do you mean "tun.kext" from > tuntaposx (http://tuntaposx.sourceforge.net), which is what > Tunnelblick uses, or are you talking about something else? Yeah exactly that one. Arne |
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-01 17:04:24
|
Thanks; now that I understand the patch, I support it. This is the first I've heard of 'utun' -- can you tell me how to load it? (I assume via "sudo kextload xxx", but what is xxx -- that is, where is the kext located?) On Mon, Apr 1, 2013 at 11:30 AM, Arne Schwabe <ar...@rf...> wrote: > Am 01.04.13 17:18, schrieb Jonathan K. Bullard: > > On Mon, Apr 1, 2013 at 11:06 AM, Arne Schwabe <ar...@rf...> wrote: >> >>> >>> The "standard" utun.ko driver is sometimes problematic (e.g. VmWare >>>>>>>> Fusion 5 and tun.ko do not work together). >>>>>>>> >>>>>>> If it is the other way around (use tun if it is available and if not, >>>> try utun) then anybody who has loaded tun will continue to work with >>>> that tun, and anybody who hasn't loaded tun will get utun if it is >>>> available. So nothing breaks. >>>> >>>> It's hard for a GUI like Tunnelblick that doesn't parse the >>>> configuration file to detect the situation (no dev-type option) to add >>>> a "dev-type tun" to force the use of tun. >>>> >>>> But if we know that utun works for OpenVPN, then I don't have any >>>> problem with the patch. But that utun "is sometimes problematic" makes >>>> me worried that this may not be the case. >>>> >>> The short history behind the patch: I was investing why Tunnelblick was >>> not working on a collegues Macbook and as it turned out that you can have >>> tun.ko loaded or the VmWare Fusion network driver (at least on his >>> Macbook). Otherwise you get errors on loading the module. But I remembered >>> something about the utun stuff, found the example code again and come up >>> with the patch. The setence from the commit should have been: >>> >>> The "standard" tun.ko driver is sometimes problematic (e.g. VmWare >>> Fusion 5 and tun.ko do not work together). >>> >>> The utun driver not be fully compatbile with behaviour of the standard >>> tun.ko driver but all my tests (IPv6, IPv4) worked so far. For 2.3.x I fine >>> with try utun first or try tun first behaviour but for -master/2.4 I would >>> like to have try utun first so more people actually use utun so we get to >>> know if it is really 100% compatible/working. >>> >> Thanks; I get it. So it is the "standard" tun driver that is a >> problem, and the utun driver fixes that problem. In that case, patch >> is OK with me. >> >> By "the 'standard' tun.ko driver", do you mean "tun.kext" from >> tuntaposx (http://tuntaposx.sourceforge.**net<http://tuntaposx.sourceforge.net>), >> which is what >> Tunnelblick uses, or are you talking about something else? >> > Yeah exactly that one. > > Arne > > |
|
From: Arne S. <ar...@rf...> - 2013-04-01 17:16:07
Attachments:
smime.p7s
|
Am 01.04.13 19:03, schrieb Jonathan K. Bullard: > Thanks; now that I understand the patch, I support it. > > This is the first I've heard of 'utun' -- can you tell me how to load it? > > There is no need for any extra kextload. Using the socket magic my patch does is enough and you need to be root. Arne |
|
From: Gert D. <ge...@gr...> - 2013-04-01 18:49:24
|
Hi,
(detouring from tun/utun, but don't let me stop you and Arne from
discussing this in the original thread)
On Mon, Apr 01, 2013 at 09:26:04AM -0400, Jonathan K. Bullard wrote:
> I don't have an opinion about including it in 2.3.2 vs. 2.4 -- I still
> can't get anything after 2.3alpha1 to build properly for Tunnelblick!
Uh. I've seen some issues reported by you, but I thought it had been
resolved in time for 2.3_RC and 2.3.0 - since we're at 2.3.1 now, I
really want to see this fixed :-)
So what is still breaking for you?
(I'm especially surprised since I know Arne is building and testing on
OSX, so it *should* work - but maybe it's "it works on 10.7 and 10.8,
but fails on 10.6", which we might have overlooked as our pool of OSX
machines with various OS releases to build on is a bit limited - how
do other open source projects handle this??)
gert
--
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany ge...@gr...
fax: +49-89-35655025 ge...@ne...
|
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-01 19:58:38
|
On Mon, Apr 1, 2013 at 2:48 PM, Gert Doering <ge...@gr...> wrote: > On Mon, Apr 01, 2013 at 09:26:04AM -0400, Jonathan K. Bullard wrote: > > I don't have an opinion about including it in 2.3.2 vs. 2.4 -- I still > > can't get anything after 2.3alpha1 to build properly for Tunnelblick! > > Uh. I've seen some issues reported by you, but I thought it had been > resolved in time for 2.3_RC and 2.3.0 - since we're at 2.3.1 now, I > really want to see this fixed :-) > > So what is still breaking for you? > > (I'm especially surprised since I know Arne is building and testing on > OSX, so it *should* work - but maybe it's "it works on 10.7 and 10.8, > but fails on 10.6", which we might have overlooked as our pool of OSX > machines with various OS releases to build on is a bit limited - how > do other open source projects handle this??) > Thanks for your inquiry. Tunnelblick is still being built on OS X 10.6.8 with Xcode 3.2.2 because it still supports PowerPC, which later versions of Xcode (which are required for use on 10.7+) don't support. (For simplicity, Tunnelblick and its dependencies are all built as a single Xcode project. Tunnelblick usually includes at least two or three versions of OpenVPN, and lets the user select which version they want to use with a couple of clicks, but of course it is limited to the versions that we can build!) I doubt that the issues are in OpenVPN itself, or its build system. I think I couldn't get it working because of my unfamiliarity with make and the toolset that is required to build OpenVPN. As I remember: - The problems happen for 2.3alpha2 but not 2.3alpha1, and I finally figured out they were triggered not by the major build-system changes, but by the initial patch that added PolarSSL. - The problems were in getting openvpn to static link with lzo and openssl. (There may have been a similar issue with pkcs11-helper, but it is broken in Tunnelblick and I later found out that it shouldn't be static linked, so that wasn't a major concern.) Harold Molina-Bulla has taken over the effort to get Tunnelblick building with OpenVPN 2.3. I've added him as a cc: to this thread. |
|
From: Arne S. <ar...@rf...> - 2013-04-02 13:47:19
|
> > Tunnelblick is still being built on OS X 10.6.8 with Xcode 3.2.2 > because it still supports PowerPC, which later versions of Xcode > (which are required for use on 10.7+) don't support. Is there a specific reason for Xcode 3.2.2? I set up a 10.6.8 snow leopard with 3.2.2 and did not have net/if_utun.h. However Xcode 3.2.6 includes net/if_utun.h and utun works on the test machine (and also include the powerpc-* gcc binaries) Arne |
|
From: Jonathan K. B. <jkb...@gm...> - 2013-04-02 18:25:30
|
On Tue, Apr 2, 2013 at 9:46 AM, Arne Schwabe <ar...@rf...> wrote: > > Tunnelblick is still being built on OS X 10.6.8 with Xcode 3.2.2 > > because it still supports PowerPC, which later versions of Xcode > > (which are required for use on 10.7+) don't support. > Is there a specific reason for Xcode 3.2.2? I set up a 10.6.8 snow > leopard with 3.2.2 and did not have net/if_utun.h. However Xcode 3.2.6 > includes net/if_utun.h and utun works on the test machine (and also > include the powerpc-* gcc binaries) > Xcode 3.2.6 does not generate PPC code for the *Tunnelblick* part (written in Objective-C). At least, it doesn't have a way to select an architecture of "Universal 32-bit" (meaning 32-bit PPC & i386), only "32-bit Intel", "64-bit Intel", or "Standard (32/64-bit Intel)". There is an "Other" setting, but I haven't been able to set that to anything that makes "Universal 32-bit" (meaning 32-bit PPC & i386). In the past I've been willing to forego 64-bit to get 32-bit PPC/Intel, but of course 32/64 PPC/Intel would be great. |
|
From: Arne S. <ar...@rf...> - 2013-06-18 05:23:20
|
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 <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 307 +++++++++++++++++++++++++++++++++++++++++------------
src/openvpn/tun.h | 5 +-
4 files changed, 255 insertions(+), 70 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..38629dd 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a speficic utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not speicifying a
+.B \-\-dev\-node
+option openvpn will try to first open utun first fallback to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..e68bc2a 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -674,7 +674,7 @@ do_ifconfig (struct tuntap *tt,
}
#endif
-
+
#if defined(TARGET_LINUX)
#ifdef ENABLE_IPROUTE
/*
@@ -1277,6 +1277,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2136,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2202,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2571,154 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_ERR, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -1;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_ERR, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -1;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ if (fd != -1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Openend utun device %s", utunname);
+
+ tt->fd = fd;
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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);
+ }
}
void
@@ -2586,13 +2751,19 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, len);
+ if (tt->is_utun)
+ return write_tun_header (tt, buf, len);
+ else
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return read (tt->fd, buf, len);
+ if (tt->is_utun)
+ return read_tun_header (tt, buf, len);
+ else
+ return read (tt->fd, buf, len);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..0481357 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -180,7 +180,10 @@ struct tuntap
#ifdef TARGET_SOLARIS
int ip_fd;
#endif
-
+
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Jonathan K. B. <jkb...@gm...> - 2013-06-20 03:18:22
|
On Tue, Jun 18, 2013 at 1:23 AM, Arne Schwabe <ar...@rf...> 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 <ps...@ig...> utun patch
> Signed-off-by: Arne Schwabe <ar...@rf...>
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.
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 08:50:28
|
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 <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 305 +++++++++++++++++++++++++++++++++++++++++------------
src/openvpn/tun.h | 3 +
4 files changed, 253 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..aee5fe2 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a speficic utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not speicifying a
+.B \-\-dev\-node
+option openvpn will try to first open utun first fallback to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..4bdedaa 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1277,6 +1277,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2136,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2202,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2571,154 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_ERR, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -1;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_ERR, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -1;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ if (fd != -1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Openend utun device %s", utunname);
+
+ tt->fd = fd;
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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);
+ }
}
void
@@ -2586,13 +2751,19 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, len);
+ if (tt->is_utun)
+ return write_tun_header (tt, buf, len);
+ else
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return read (tt->fd, buf, len);
+ if (tt->is_utun)
+ return read_tun_header (tt, buf, len);
+ else
+ return read (tt->fd, buf, len);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 09:05:16
|
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 <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 310 +++++++++++++++++++++++++++++++++++++++++------------
src/openvpn/tun.h | 3 +
4 files changed, 258 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..1877294 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..ad80120 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1277,6 +1277,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2136,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2202,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2571,155 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_WARN, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -1;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_WARN, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -1;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ if (fd != -1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+
+ tt->fd = fd;
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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);
+ }
}
void
@@ -2586,13 +2752,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, 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)
{
- return read (tt->fd, buf, 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);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Jonathan K. B. <jkb...@gm...> - 2013-06-20 13:33:41
|
On Thu, Jun 20, 2013 at 4:58 AM, Arne Schwabe <ar...@rf...> wrote:
> I have a OS X 10.6 VM with Xcode 3.2.6 installed and this VM has the
> if/utun.h header. I probably was added somewhere between 10.6.0 and 10.6.8.
Ah. Thanks for mentioning this. That makes sense.
> I changed the M_ERR to M_WARN. It should now work on 10.5.x but without
> a 10.5 to test on it is difficult to say...
OK, thanks; now I better understand how the error handling works.
On Thu, Jun 20, 2013 at 5:05 AM, Arne Schwabe <ar...@rf...> 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 <ps...@ig...> utun patch
> Signed-off-by: Arne Schwabe <ar...@rf...>
First, I should mention that the most recent version of this patch (in
your Thu, Jun 20, 2013 at 5:05 AM email) seems to make some other,
major changes, too, at least when compared to the earlier version (in
your email of Tue, Jun 18, 2013 at 1:23 AM). I have ignored those
changes (I don't really understand them), and I have just made the
changes that I mentioned, plus one typo that you caught that I missed,
and the M_ERR to M_WARN changes.
Unfortunately, this patch still fails if the utun code is included and
executed on 10.5.
A minor problem is that for each of the 255 attempts to get a utun
device (device #0 through device #254), it generates the following
warning message:
Opening utun (ioctl(CTLIOCGINFO)): No such file or directory
It's ugly, but cosmetic. Perhaps it could be displayed only at verb=4
and higher? (I don't know how to do that.)
The larger problem is that it still fails to connect, with the error message:
Error retrieving utun interface name: Bad file descriptor (errno=9)
I think this is because open_darwin_utun ignores the error (fd == -1)
returned from utun_open_helper.
If so, it can be fixed by changing open_darwin_utun as follows:
else
{
fd = utun_open_helper (ctlInfo, utunnum);
}
+ if (fd==-1)
+ tt->is_utun = false;
+ return;
+
/* Retrieve the assigned interface name. */
if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname,
&utunname_len))
msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
tt->actual_name = string_alloc (utunname, NULL);
(I added the " tt->is_utun = false;" just to be sure; I'm not clear on
the initialization of tt->is_utun, and it is used in the test that
follows the call to open_darwin_utun to test for success/failure.)
After making that change, it works on OS X 10.5.8 and 10.4.11.
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 13:59:22
|
Am 20.06.13 15:32, schrieb Jonathan K. Bullard:
> A minor problem is that for each of the 255 attempts to get a utun
> device (device #0 through device #254), it generates the following
> warning message:
> Opening utun (ioctl(CTLIOCGINFO)): No such file or directory
> It's ugly, but cosmetic. Perhaps it could be displayed only at verb=4
> and higher? (I don't know how to do that.)
I have changed the patch to only try to open that once in case of early
initialization failure. I also change the log level to M_INFO.
>
> The larger problem is that it still fails to connect, with the error message:
> Error retrieving utun interface name: Bad file descriptor (errno=9)
>
> I think this is because open_darwin_utun ignores the error (fd == -1)
> returned from utun_open_helper.
fd == -1 was overloaded in
- utun failed to open at all
- this specific utun failed (like utun1, utun2, ....)
>
> If so, it can be fixed by changing open_darwin_utun as follows:
>
> else
> {
> fd = utun_open_helper (ctlInfo, utunnum);
> }
>
> + if (fd==-1)
> + tt->is_utun = false;
> + return;
> +
> /* Retrieve the assigned interface name. */
> if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname,
> &utunname_len))
> msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
>
> tt->actual_name = string_alloc (utunname, NULL);
>
> (I added the " tt->is_utun = false;" just to be sure; I'm not clear on
> the initialization of tt->is_utun, and it is used in the test that
> follows the call to open_darwin_utun to test for success/failure.)
>
Thanks for spotting this.
Arne
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 14:00:09
|
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
A lot good input on earlier patches by Jonathan K. Bullard <jkb...@gm...>
Parts of the patches are inspired from Peter Sagerson's <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 326 ++++++++++++++++++++++++++++++++++++++++++-----------
src/openvpn/tun.h | 3 +
4 files changed, 274 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..1877294 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..39482d5 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1277,6 +1277,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2136,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2202,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2571,171 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_WARN, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_WARN, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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
+ {
+ /* Specific utun device or generic utun request failed,
+ consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ 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);
+ }
}
void
@@ -2586,13 +2768,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, 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)
{
- return read (tt->fd, buf, 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);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 14:22:12
|
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
A lot good input on earlier patches by Jonathan K. Bullard <jkb...@gm...>
Parts of the patches are inspired from Peter Sagerson's <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 330 ++++++++++++++++++++++++++++++++++++++++++-----------
src/openvpn/tun.h | 3 +
4 files changed, 278 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..1877294 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..80a75b4 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1277,6 +1277,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2136,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2202,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2571,175 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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);
+
+
+ if (!tt->is_utun)
+ {
+ if (!dev_node)
+ {
+ /* No explicit utun and utun failed, try the generic way) */
+ 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
+ {
+ /* Specific utun device or generic utun request failed,
+ consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ }
+ 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);
+ }
}
void
@@ -2586,13 +2772,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, 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)
{
- return read (tt->fd, buf, 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);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Arne S. <ar...@rf...> - 2013-06-20 14:38:54
|
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
v2: Fixed tap support, get device name via ioctl, add manage
v3.1: Fix compiling without if/utun.h, fix manage errors
v4/v5: Don't try open to dynamically open utun0 -255 when early utun initialization fails, fix fallback to tun, give fatal error message when utun fails but no tun fallback should be done
v6: add commit message change log, replace strstr with strncmp, move #includes to the top of the file
A lot good input on earlier patches by Jonathan K. Bullard <jkb...@gm...>
Parts of the patches are inspired from Peter Sagerson's <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 333 ++++++++++++++++++++++++++++++++++++++++++-----------
src/openvpn/tun.h | 3 +
4 files changed, 281 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 397e2bf..1877294 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..3316bc6 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -74,6 +74,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co
#include <stropts.h>
#endif
+#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+#endif
+
static void clear_tuntap (struct tuntap *tuntap);
bool
@@ -1277,6 +1283,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2142,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2208,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2577,172 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, 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 && !strncmp (dev_node, "utun", 4)))
+ {
+ /* 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);
+
+
+ if (!tt->is_utun)
+ {
+ if (!dev_node)
+ {
+ /* No explicit utun and utun failed, try the generic way) */
+ 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
+ {
+ /* Specific utun device or generic utun request failed,
+ consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ }
+ 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);
+ }
}
void
@@ -2586,13 +2775,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, 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)
{
- return read (tt->fd, buf, 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);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|
|
From: Gert D. <ge...@gr...> - 2013-06-20 19:23:58
|
Hi,
On Thu, Jun 20, 2013 at 04:38:43PM +0200, Arne Schwabe 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).
James brought up a "we need a v7 here"...
If you call "openvpn --dev tap --dev-node utun0", I think the current
code will open an utun device, but the rest of OpenVPN will expect it
to be tappish...
21:18 <@jamesyonan> if utun doesn't support tap, then we need to make sure that
code will fall back to tuntap driver for tap tunnels
... so, two options
a) utun can do TAP - in that case we need to add the necessary magic bits
to convert the newly created utun into an utap
b) it can not do TAP (which I'd expect, tbh), so we should never open
an utun device if the user wants a tap.
Arne, your call :-)
gert
--
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany ge...@gr...
fax: +49-89-35655025 ge...@ne...
|
|
From: Arne S. <ar...@rf...> - 2013-06-21 10:48:39
|
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
v2: Fixed tap support, get device name via ioctl, add manage
v3.1: Fix compiling without if/utun.h, fix manage errors
v4/v5: Don't try open to dynamically open utun0 -255 when early utun initialization fails, fix fallback to tun, give fatal error message when utun fails but no tun fallback should be done
v6: add commit message change log, replace strstr with strncmp, move #includes to the top of the file
v7: Throw error if a user does the strange combination of --dev tun --dev-type tap and --dev-node utun
A lot good input on earlier patches by Jonathan K. Bullard <jkb...@gm...>
Parts of the patches are inspired from Peter Sagerson's <ps...@ig...> utun patch
Signed-off-by: Arne Schwabe <ar...@rf...>
---
configure.ac | 2 +-
doc/openvpn.8 | 11 ++
src/openvpn/tun.c | 338 ++++++++++++++++++++++++++++++++++++++++++-----------
src/openvpn/tun.h | 3 +
4 files changed, 286 insertions(+), 68 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5da5772..854cfbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -459,7 +459,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 174fd6d..949577b 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -805,6 +805,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index f7443b4..18afa3f 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -74,6 +74,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co
#include <stropts.h>
#endif
+#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+#endif
+
static void clear_tuntap (struct tuntap *tuntap);
bool
@@ -1277,6 +1283,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2055,23 +2142,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2138,59 +2208,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2550,10 +2577,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+#ifdef HAVE_NET_IF_UTUN_H
+ /* If dev_node does not start start with utun assume regular tun/tap */
+ if ((!dev_node && tt->type==DEV_TYPE_TUN) ||
+ (dev_node && !strncmp (dev_node, "utun", 4)))
+ {
+
+ /* Check if user has specific dev_type tap and forced utun with
+ dev-node utun */
+ if (tt->type!=DEV_TYPE_TUN)
+ msg (M_FATAL, "Cannot use utun devices with --dev-type %s",
+ dev_type_string (dev, dev_type));
+
+ /* 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);
+
+ if (!tt->is_utun)
+ {
+ if (!dev_node)
+ {
+ /* No explicit utun and utun failed, try the generic way) */
+ 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
+ {
+ /* Specific utun device or generic utun request with no tun
+ fall back failed, consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ }
+ 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);
+ }
}
void
@@ -2586,13 +2780,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, 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)
{
- return read (tt->fd, buf, 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);
}
#elif defined(WIN32)
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 956ad8d..2c97ffe 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
--
1.7.9.5
|