Support utun devices on Mac OS X.
As of 10.6, OS X has native tunnel devices. They are implemented as sockets rather than character devices, but otherwise they appear to behave the same as Free/OpenBSD tunnels. '-d utunX' will tell iodine to use a utun device. For backward compatibility, we'll continue to default to the old tuntap devices for now. This is a port of Peter Sagerson <psagers.github@ignorare.net>'s openvpn commit 43e5016a.
This commit is contained in:
parent
1160649794
commit
33abc0ca26
168
src/tun.c
168
src/tun.c
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
|
* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
|
||||||
* 2006-2009 Bjorn Andersson <flex@kryo.se>
|
* 2006-2009 Bjorn Andersson <flex@kryo.se>
|
||||||
|
* 2013 Peter Sagerson <psagers.github@ignorare.net>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -25,6 +26,15 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#ifdef DARWIN
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/kern_control.h>
|
||||||
|
#include <sys/sys_domain.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if_utun.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef IFCONFIGPATH
|
#ifndef IFCONFIGPATH
|
||||||
#define IFCONFIGPATH "PATH=/sbin:/bin "
|
#define IFCONFIGPATH "PATH=/sbin:/bin "
|
||||||
#endif
|
#endif
|
||||||
|
@ -315,6 +325,86 @@ open_tun(const char *tun_device)
|
||||||
|
|
||||||
#else /* BSD and friends */
|
#else /* BSD and friends */
|
||||||
|
|
||||||
|
#ifdef DARWIN
|
||||||
|
|
||||||
|
/* Extract the device number from the name, if given. The value returned will
|
||||||
|
* be suitable for sockaddr_ctl.sc_unit, which means 0 for auto-assign, or
|
||||||
|
* (n + 1) for manual.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
utun_unit(const char *dev)
|
||||||
|
{
|
||||||
|
const char *unit_str = dev;
|
||||||
|
int unit = 0;
|
||||||
|
|
||||||
|
while (*unit_str != '\0' && !isdigit(*unit_str))
|
||||||
|
unit_str++;
|
||||||
|
|
||||||
|
if (isdigit(*unit_str))
|
||||||
|
unit = strtol(unit_str, NULL, 10) + 1;
|
||||||
|
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
open_utun(const char *dev)
|
||||||
|
{
|
||||||
|
struct sockaddr_ctl addr;
|
||||||
|
struct ctl_info info;
|
||||||
|
char ifname[10];
|
||||||
|
socklen_t ifname_len = sizeof(ifname);
|
||||||
|
int fd = -1;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||||
|
if (fd < 0) {
|
||||||
|
warn("open_utun: socket(PF_SYSTEM)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look up the kernel controller ID for utun devices. */
|
||||||
|
bzero(&info, sizeof(info));
|
||||||
|
strncpy(info.ctl_name, UTUN_CONTROL_NAME, MAX_KCTL_NAME);
|
||||||
|
|
||||||
|
err = ioctl(fd, CTLIOCGINFO, &info);
|
||||||
|
if (err != 0) {
|
||||||
|
warn("open_utun: ioctl(CTLIOCGINFO)");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connecting to the socket creates the utun device. */
|
||||||
|
addr.sc_len = sizeof(addr);
|
||||||
|
addr.sc_family = AF_SYSTEM;
|
||||||
|
addr.ss_sysaddr = AF_SYS_CONTROL;
|
||||||
|
addr.sc_id = info.ctl_id;
|
||||||
|
addr.sc_unit = utun_unit(dev);
|
||||||
|
|
||||||
|
err = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
if (err != 0) {
|
||||||
|
warn("open_utun: connect");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve the assigned interface name. */
|
||||||
|
err = getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, ifname, &ifname_len);
|
||||||
|
if (err != 0) {
|
||||||
|
warn("open_utun: getsockopt(UTUN_OPT_IFNAME)");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(if_name, ifname, sizeof(if_name));
|
||||||
|
|
||||||
|
fprintf(stderr, "Opened %s\n", ifname);
|
||||||
|
fd_set_close_on_exec(fd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
open_tun(const char *tun_device)
|
open_tun(const char *tun_device)
|
||||||
{
|
{
|
||||||
|
@ -322,6 +412,15 @@ open_tun(const char *tun_device)
|
||||||
int tun_fd;
|
int tun_fd;
|
||||||
char tun_name[50];
|
char tun_name[50];
|
||||||
|
|
||||||
|
#ifdef DARWIN
|
||||||
|
if (!strncmp(tun_device, "utun", 4)) {
|
||||||
|
tun_fd = open_utun(tun_device);
|
||||||
|
if (tun_fd >= 0) {
|
||||||
|
return tun_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (tun_device != NULL) {
|
if (tun_device != NULL) {
|
||||||
snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
|
snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
|
||||||
strncpy(if_name, tun_device, sizeof(if_name));
|
strncpy(if_name, tun_device, sizeof(if_name));
|
||||||
|
@ -407,22 +506,32 @@ read_tun(int tun_fd, char *buf, size_t len)
|
||||||
int
|
int
|
||||||
write_tun(int tun_fd, char *data, size_t len)
|
write_tun(int tun_fd, char *data, size_t len)
|
||||||
{
|
{
|
||||||
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
|
#if defined (FREEBSD) || defined (NETBSD)
|
||||||
data += 4;
|
/* FreeBSD/NetBSD has no header */
|
||||||
len -= 4;
|
int header = 0;
|
||||||
#else /* !FREEBSD/DARWIN */
|
#elif defined (DARWIN)
|
||||||
|
/* Darwin tun has no header, Darwin utun does */
|
||||||
|
int header = !strncmp(if_name, "utun", 4);
|
||||||
|
#else /* LINUX/OPENBSD */
|
||||||
|
int header = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!header) {
|
||||||
|
data += 4;
|
||||||
|
len -= 4;
|
||||||
|
} else {
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
data[0] = 0x00;
|
data[0] = 0x00;
|
||||||
data[1] = 0x00;
|
data[1] = 0x00;
|
||||||
data[2] = 0x08;
|
data[2] = 0x08;
|
||||||
data[3] = 0x00;
|
data[3] = 0x00;
|
||||||
#else /* OPENBSD */
|
#else /* OPENBSD */
|
||||||
data[0] = 0x00;
|
data[0] = 0x00;
|
||||||
data[1] = 0x00;
|
data[1] = 0x00;
|
||||||
data[2] = 0x00;
|
data[2] = 0x00;
|
||||||
data[3] = 0x02;
|
data[3] = 0x02;
|
||||||
#endif /* !LINUX */
|
#endif
|
||||||
#endif /* FREEBSD */
|
}
|
||||||
|
|
||||||
if (write(tun_fd, data, len) != len) {
|
if (write(tun_fd, data, len) != len) {
|
||||||
warn("write_tun");
|
warn("write_tun");
|
||||||
|
@ -434,20 +543,29 @@ write_tun(int tun_fd, char *data, size_t len)
|
||||||
ssize_t
|
ssize_t
|
||||||
read_tun(int tun_fd, char *buf, size_t len)
|
read_tun(int tun_fd, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
|
#if defined (FREEBSD) || defined (NETBSD)
|
||||||
/* FreeBSD/Darwin/NetBSD has no header */
|
/* FreeBSD/NetBSD has no header */
|
||||||
int bytes;
|
int header = 0;
|
||||||
memset(buf, 0, 4);
|
#elif defined (DARWIN)
|
||||||
|
/* Darwin tun has no header, Darwin utun does */
|
||||||
|
int header = !strncmp(if_name, "utun", 4);
|
||||||
|
#else /* LINUX/OPENBSD */
|
||||||
|
int header = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
bytes = read(tun_fd, buf + 4, len - 4);
|
if (!header) {
|
||||||
if (bytes < 0) {
|
int bytes;
|
||||||
return bytes;
|
memset(buf, 0, 4);
|
||||||
|
|
||||||
|
bytes = read(tun_fd, buf + 4, len - 4);
|
||||||
|
if (bytes < 0) {
|
||||||
|
return bytes;
|
||||||
|
} else {
|
||||||
|
return bytes + 4;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return bytes + 4;
|
return read(tun_fd, buf, len);
|
||||||
}
|
}
|
||||||
#else /* !FREEBSD */
|
|
||||||
return read(tun_fd, buf, len);
|
|
||||||
#endif /* !FREEBSD */
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue