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
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
<jkbullard@gmail.com>
Parts of the patches are inspired from Peter Sagerson's
<psagers@ignorare.net> utun patch
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Tested-by: Jonathan K. Bullard <jkbullard@gmail.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1371811708-8528-1-git-send-email-arne@rfc2549.org>
URL: http://article.gmane.org/gmane.network.openvpn.devel/7739
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit fbc04bedbcce02fc625357b7475ddbc7164cabbf)
... | ... |
@@ -454,7 +454,7 @@ SOCKET_INCLUDES=" |
454 | 454 |
" |
455 | 455 |
|
456 | 456 |
AC_CHECK_HEADERS( |
457 |
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h], |
|
457 |
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h], |
|
458 | 458 |
, |
459 | 459 |
, |
460 | 460 |
[[${SOCKET_INCLUDES}]] |
... | ... |
@@ -805,6 +805,17 @@ also specify |
805 | 805 |
or |
806 | 806 |
.B \-\-dev-type tap. |
807 | 807 |
|
808 |
+Under Mac OS X this option can be used to specify the default tun |
|
809 |
+implementation. Using |
|
810 |
+.B \-\-dev\-node utun |
|
811 |
+forces usage of the native Darwin tun kernel support. Use |
|
812 |
+.B \-\-dev\-node utunN |
|
813 |
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use |
|
814 |
+.B \-\-dev\-node tun |
|
815 |
+. When not specifying a |
|
816 |
+.B \-\-dev\-node |
|
817 |
+option openvpn will first try to open utun, and fall back to tun.kext. |
|
818 |
+ |
|
808 | 819 |
On Windows systems, select the TAP-Win32 adapter which |
809 | 820 |
is named |
810 | 821 |
.B node |
... | ... |
@@ -73,6 +73,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co |
73 | 73 |
#include <stropts.h> |
74 | 74 |
#endif |
75 | 75 |
|
76 |
+#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H |
|
77 |
+#include <sys/kern_control.h> |
|
78 |
+#include <net/if_utun.h> |
|
79 |
+#include <sys/sys_domain.h> |
|
80 |
+#endif |
|
81 |
+ |
|
76 | 82 |
static void clear_tuntap (struct tuntap *tuntap); |
77 | 83 |
|
78 | 84 |
bool |
... | ... |
@@ -1248,6 +1254,87 @@ open_null (struct tuntap *tt) |
1248 | 1248 |
tt->actual_name = string_alloc ("null", NULL); |
1249 | 1249 |
} |
1250 | 1250 |
|
1251 |
+ |
|
1252 |
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) |
|
1253 |
+ |
|
1254 |
+/* |
|
1255 |
+ * OpenBSD and Mac OS X when using utun |
|
1256 |
+ * have a slightly incompatible TUN device from |
|
1257 |
+ * the rest of the world, in that it prepends a |
|
1258 |
+ * uint32 to the beginning of the IP header |
|
1259 |
+ * to designate the protocol (why not just |
|
1260 |
+ * look at the version field in the IP header to |
|
1261 |
+ * determine v4 or v6?). |
|
1262 |
+ * |
|
1263 |
+ * We strip off this field on reads and |
|
1264 |
+ * put it back on writes. |
|
1265 |
+ * |
|
1266 |
+ * I have not tested TAP devices on OpenBSD, |
|
1267 |
+ * but I have conditionalized the special |
|
1268 |
+ * TUN handling code described above to |
|
1269 |
+ * go away for TAP devices. |
|
1270 |
+ */ |
|
1271 |
+ |
|
1272 |
+#include <netinet/ip.h> |
|
1273 |
+#include <sys/uio.h> |
|
1274 |
+ |
|
1275 |
+static inline int |
|
1276 |
+header_modify_read_write_return (int len) |
|
1277 |
+{ |
|
1278 |
+ if (len > 0) |
|
1279 |
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; |
|
1280 |
+ else |
|
1281 |
+ return len; |
|
1282 |
+} |
|
1283 |
+ |
|
1284 |
+int |
|
1285 |
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len) |
|
1286 |
+{ |
|
1287 |
+ if (tt->type == DEV_TYPE_TUN) |
|
1288 |
+ { |
|
1289 |
+ u_int32_t type; |
|
1290 |
+ struct iovec iv[2]; |
|
1291 |
+ struct ip *iph; |
|
1292 |
+ |
|
1293 |
+ iph = (struct ip *) buf; |
|
1294 |
+ |
|
1295 |
+ if (tt->ipv6 && iph->ip_v == 6) |
|
1296 |
+ type = htonl (AF_INET6); |
|
1297 |
+ else |
|
1298 |
+ type = htonl (AF_INET); |
|
1299 |
+ |
|
1300 |
+ iv[0].iov_base = &type; |
|
1301 |
+ iv[0].iov_len = sizeof (type); |
|
1302 |
+ iv[1].iov_base = buf; |
|
1303 |
+ iv[1].iov_len = len; |
|
1304 |
+ |
|
1305 |
+ return header_modify_read_write_return (writev (tt->fd, iv, 2)); |
|
1306 |
+ } |
|
1307 |
+ else |
|
1308 |
+ return write (tt->fd, buf, len); |
|
1309 |
+} |
|
1310 |
+ |
|
1311 |
+int |
|
1312 |
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len) |
|
1313 |
+{ |
|
1314 |
+ if (tt->type == DEV_TYPE_TUN) |
|
1315 |
+ { |
|
1316 |
+ u_int32_t type; |
|
1317 |
+ struct iovec iv[2]; |
|
1318 |
+ |
|
1319 |
+ iv[0].iov_base = &type; |
|
1320 |
+ iv[0].iov_len = sizeof (type); |
|
1321 |
+ iv[1].iov_base = buf; |
|
1322 |
+ iv[1].iov_len = len; |
|
1323 |
+ |
|
1324 |
+ return header_modify_read_write_return (readv (tt->fd, iv, 2)); |
|
1325 |
+ } |
|
1326 |
+ else |
|
1327 |
+ return read (tt->fd, buf, len); |
|
1328 |
+} |
|
1329 |
+#endif |
|
1330 |
+ |
|
1331 |
+ |
|
1251 | 1332 |
#ifndef WIN32 |
1252 | 1333 |
static void |
1253 | 1334 |
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, |
... | ... |
@@ -1972,23 +2059,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) |
1972 | 1972 |
|
1973 | 1973 |
#elif defined(TARGET_OPENBSD) |
1974 | 1974 |
|
1975 |
-/* |
|
1976 |
- * OpenBSD has a slightly incompatible TUN device from |
|
1977 |
- * the rest of the world, in that it prepends a |
|
1978 |
- * uint32 to the beginning of the IP header |
|
1979 |
- * to designate the protocol (why not just |
|
1980 |
- * look at the version field in the IP header to |
|
1981 |
- * determine v4 or v6?). |
|
1982 |
- * |
|
1983 |
- * We strip off this field on reads and |
|
1984 |
- * put it back on writes. |
|
1985 |
- * |
|
1986 |
- * I have not tested TAP devices on OpenBSD, |
|
1987 |
- * but I have conditionalized the special |
|
1988 |
- * TUN handling code described above to |
|
1989 |
- * go away for TAP devices. |
|
1990 |
- */ |
|
1991 |
- |
|
1992 | 1975 |
void |
1993 | 1976 |
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) |
1994 | 1977 |
{ |
... | ... |
@@ -2055,59 +2125,16 @@ close_tun (struct tuntap* tt) |
2055 | 2055 |
} |
2056 | 2056 |
} |
2057 | 2057 |
|
2058 |
-static inline int |
|
2059 |
-openbsd_modify_read_write_return (int len) |
|
2060 |
-{ |
|
2061 |
- if (len > 0) |
|
2062 |
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; |
|
2063 |
- else |
|
2064 |
- return len; |
|
2065 |
-} |
|
2066 |
- |
|
2067 | 2058 |
int |
2068 |
-write_tun (struct tuntap* tt, uint8_t *buf, int len) |
|
2059 |
+write_tun(struct tuntap *tt, uint8_t *buf, int len) |
|
2069 | 2060 |
{ |
2070 |
- if (tt->type == DEV_TYPE_TUN) |
|
2071 |
- { |
|
2072 |
- u_int32_t type; |
|
2073 |
- struct iovec iv[2]; |
|
2074 |
- struct ip *iph; |
|
2075 |
- |
|
2076 |
- iph = (struct ip *) buf; |
|
2077 |
- |
|
2078 |
- if (tt->ipv6 && iph->ip_v == 6) |
|
2079 |
- type = htonl (AF_INET6); |
|
2080 |
- else |
|
2081 |
- type = htonl (AF_INET); |
|
2082 |
- |
|
2083 |
- iv[0].iov_base = &type; |
|
2084 |
- iv[0].iov_len = sizeof (type); |
|
2085 |
- iv[1].iov_base = buf; |
|
2086 |
- iv[1].iov_len = len; |
|
2087 |
- |
|
2088 |
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); |
|
2089 |
- } |
|
2090 |
- else |
|
2091 |
- return write (tt->fd, buf, len); |
|
2061 |
+ return write_tun_header (tt, buf, len); |
|
2092 | 2062 |
} |
2093 | 2063 |
|
2094 | 2064 |
int |
2095 |
-read_tun (struct tuntap* tt, uint8_t *buf, int len) |
|
2065 |
+read_tun (struct tuntap *tt, uint8_t *buf, int len) |
|
2096 | 2066 |
{ |
2097 |
- if (tt->type == DEV_TYPE_TUN) |
|
2098 |
- { |
|
2099 |
- u_int32_t type; |
|
2100 |
- struct iovec iv[2]; |
|
2101 |
- |
|
2102 |
- iv[0].iov_base = &type; |
|
2103 |
- iv[0].iov_len = sizeof (type); |
|
2104 |
- iv[1].iov_base = buf; |
|
2105 |
- iv[1].iov_len = len; |
|
2106 |
- |
|
2107 |
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); |
|
2108 |
- } |
|
2109 |
- else |
|
2110 |
- return read (tt->fd, buf, len); |
|
2067 |
+ return read_tun_header (tt, buf, len); |
|
2111 | 2068 |
} |
2112 | 2069 |
|
2113 | 2070 |
#elif defined(TARGET_NETBSD) |
... | ... |
@@ -2467,10 +2494,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) |
2467 | 2467 |
* pointing to lo0. Need to unconfigure... (observed on 10.5) |
2468 | 2468 |
*/ |
2469 | 2469 |
|
2470 |
+/* |
|
2471 |
+ * utun is the native Darwin tun driver present since at least 10.7 |
|
2472 |
+ * Thanks goes to Jonathan Levin for providing an example how to utun |
|
2473 |
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c) |
|
2474 |
+ */ |
|
2475 |
+ |
|
2476 |
+#ifdef HAVE_NET_IF_UTUN_H |
|
2477 |
+ |
|
2478 |
+/* Helper functions that tries to open utun device |
|
2479 |
+ return -2 on early initialization failures (utun not supported |
|
2480 |
+ at all (old OS X) and -1 on initlization failure of utun |
|
2481 |
+ device (utun works but utunX is already used */ |
|
2482 |
+static |
|
2483 |
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum) |
|
2484 |
+{ |
|
2485 |
+ struct sockaddr_ctl sc; |
|
2486 |
+ int fd; |
|
2487 |
+ |
|
2488 |
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); |
|
2489 |
+ |
|
2490 |
+ if (fd < 0) |
|
2491 |
+ { |
|
2492 |
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", |
|
2493 |
+ strerror (errno)); |
|
2494 |
+ return -2; |
|
2495 |
+ } |
|
2496 |
+ |
|
2497 |
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) |
|
2498 |
+ { |
|
2499 |
+ close (fd); |
|
2500 |
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", |
|
2501 |
+ strerror (errno)); |
|
2502 |
+ return -2; |
|
2503 |
+ } |
|
2504 |
+ |
|
2505 |
+ |
|
2506 |
+ sc.sc_id = ctlInfo.ctl_id; |
|
2507 |
+ sc.sc_len = sizeof(sc); |
|
2508 |
+ sc.sc_family = AF_SYSTEM; |
|
2509 |
+ sc.ss_sysaddr = AF_SYS_CONTROL; |
|
2510 |
+ |
|
2511 |
+ sc.sc_unit = utunnum+1; |
|
2512 |
+ |
|
2513 |
+ |
|
2514 |
+ /* If the connect is successful, a utun%d device will be created, where "%d" |
|
2515 |
+ * is (sc.sc_unit - 1) */ |
|
2516 |
+ |
|
2517 |
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) |
|
2518 |
+ { |
|
2519 |
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", |
|
2520 |
+ strerror (errno)); |
|
2521 |
+ close(fd); |
|
2522 |
+ return -1; |
|
2523 |
+ } |
|
2524 |
+ |
|
2525 |
+ set_nonblock (fd); |
|
2526 |
+ set_cloexec (fd); /* don't pass fd to scripts */ |
|
2527 |
+ |
|
2528 |
+ return fd; |
|
2529 |
+} |
|
2530 |
+ |
|
2531 |
+void |
|
2532 |
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) |
|
2533 |
+{ |
|
2534 |
+ struct ctl_info ctlInfo; |
|
2535 |
+ int fd; |
|
2536 |
+ char utunname[20]; |
|
2537 |
+ int utunnum =-1; |
|
2538 |
+ socklen_t utunname_len = sizeof(utunname); |
|
2539 |
+ |
|
2540 |
+ /* dev_node is simply utun, do the normal dynamic utun |
|
2541 |
+ * otherwise try to parse the utun number */ |
|
2542 |
+ if (dev_node && !strcmp ("utun", dev_node)==0) |
|
2543 |
+ { |
|
2544 |
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1) |
|
2545 |
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" |
|
2546 |
+ "to use a utun device number X", dev_node); |
|
2547 |
+ } |
|
2548 |
+ |
|
2549 |
+ |
|
2550 |
+ |
|
2551 |
+ CLEAR (ctlInfo); |
|
2552 |
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= |
|
2553 |
+ sizeof(ctlInfo.ctl_name)) |
|
2554 |
+ { |
|
2555 |
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); |
|
2556 |
+ } |
|
2557 |
+ |
|
2558 |
+ /* try to open first available utun device if no specific utun is requested */ |
|
2559 |
+ if (utunnum == -1) |
|
2560 |
+ { |
|
2561 |
+ for (utunnum=0; utunnum<255; utunnum++) |
|
2562 |
+ { |
|
2563 |
+ fd = utun_open_helper (ctlInfo, utunnum); |
|
2564 |
+ /* Break if the fd is valid, |
|
2565 |
+ * or if early initalization failed (-2) */ |
|
2566 |
+ if (fd !=-1) |
|
2567 |
+ break; |
|
2568 |
+ } |
|
2569 |
+ } |
|
2570 |
+ else |
|
2571 |
+ { |
|
2572 |
+ fd = utun_open_helper (ctlInfo, utunnum); |
|
2573 |
+ } |
|
2574 |
+ |
|
2575 |
+ /* opening an utun device failed */ |
|
2576 |
+ tt->fd = fd; |
|
2577 |
+ |
|
2578 |
+ if (fd < 0) |
|
2579 |
+ return; |
|
2580 |
+ |
|
2581 |
+ /* Retrieve the assigned interface name. */ |
|
2582 |
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) |
|
2583 |
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name"); |
|
2584 |
+ |
|
2585 |
+ tt->actual_name = string_alloc (utunname, NULL); |
|
2586 |
+ |
|
2587 |
+ msg (M_INFO, "Opened utun device %s", utunname); |
|
2588 |
+ tt->is_utun = true; |
|
2589 |
+} |
|
2590 |
+ |
|
2591 |
+#endif |
|
2592 |
+ |
|
2470 | 2593 |
void |
2471 | 2594 |
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) |
2472 | 2595 |
{ |
2473 |
- open_tun_generic (dev, dev_type, dev_node, true, true, tt); |
|
2596 |
+#ifdef HAVE_NET_IF_UTUN_H |
|
2597 |
+ /* If dev_node does not start start with utun assume regular tun/tap */ |
|
2598 |
+ if ((!dev_node && tt->type==DEV_TYPE_TUN) || |
|
2599 |
+ (dev_node && !strncmp (dev_node, "utun", 4))) |
|
2600 |
+ { |
|
2601 |
+ |
|
2602 |
+ /* Check if user has specific dev_type tap and forced utun with |
|
2603 |
+ dev-node utun */ |
|
2604 |
+ if (tt->type!=DEV_TYPE_TUN) |
|
2605 |
+ msg (M_FATAL, "Cannot use utun devices with --dev-type %s", |
|
2606 |
+ dev_type_string (dev, dev_type)); |
|
2607 |
+ |
|
2608 |
+ /* Try utun first and fall back to normal tun if utun fails |
|
2609 |
+ and dev_node is not specified */ |
|
2610 |
+ open_darwin_utun(dev, dev_type, dev_node, tt); |
|
2611 |
+ |
|
2612 |
+ if (!tt->is_utun) |
|
2613 |
+ { |
|
2614 |
+ if (!dev_node) |
|
2615 |
+ { |
|
2616 |
+ /* No explicit utun and utun failed, try the generic way) */ |
|
2617 |
+ msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); |
|
2618 |
+ open_tun_generic (dev, dev_type, NULL, true, true, tt); |
|
2619 |
+ } |
|
2620 |
+ else |
|
2621 |
+ { |
|
2622 |
+ /* Specific utun device or generic utun request with no tun |
|
2623 |
+ fall back failed, consider this a fatal failure */ |
|
2624 |
+ msg (M_FATAL, "Cannot open utun device"); |
|
2625 |
+ } |
|
2626 |
+ } |
|
2627 |
+ } |
|
2628 |
+ else |
|
2629 |
+#endif |
|
2630 |
+ { |
|
2631 |
+ |
|
2632 |
+ /* Use plain dev-node tun to select /dev/tun style |
|
2633 |
+ * Unset dev_node variable prior to passing to open_tun_generic to |
|
2634 |
+ * let open_tun_generic pick the first available tun device */ |
|
2635 |
+ |
|
2636 |
+ if (dev_node && strcmp (dev_node, "tun")==0) |
|
2637 |
+ dev_node=NULL; |
|
2638 |
+ |
|
2639 |
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt); |
|
2640 |
+ } |
|
2474 | 2641 |
} |
2475 | 2642 |
|
2476 | 2643 |
void |
... | ... |
@@ -2503,13 +2697,23 @@ close_tun (struct tuntap* tt) |
2503 | 2503 |
int |
2504 | 2504 |
write_tun (struct tuntap* tt, uint8_t *buf, int len) |
2505 | 2505 |
{ |
2506 |
- return write (tt->fd, buf, len); |
|
2506 |
+#ifdef HAVE_NET_IF_UTUN_H |
|
2507 |
+ if (tt->is_utun) |
|
2508 |
+ return write_tun_header (tt, buf, len); |
|
2509 |
+ else |
|
2510 |
+#endif |
|
2511 |
+ return write (tt->fd, buf, len); |
|
2507 | 2512 |
} |
2508 | 2513 |
|
2509 | 2514 |
int |
2510 | 2515 |
read_tun (struct tuntap* tt, uint8_t *buf, int len) |
2511 | 2516 |
{ |
2512 |
- return read (tt->fd, buf, len); |
|
2517 |
+#ifdef HAVE_NET_IF_UTUN_H |
|
2518 |
+ if (tt->is_utun) |
|
2519 |
+ return read_tun_header (tt, buf, len); |
|
2520 |
+ else |
|
2521 |
+#endif |
|
2522 |
+ return read (tt->fd, buf, len); |
|
2513 | 2523 |
} |
2514 | 2524 |
|
2515 | 2525 |
#elif defined(WIN32) |