Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add utun for darwin #16

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 80 additions & 10 deletions tuntap-unix-darwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/errno.h>

#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_utun.h> /* TODO: Detection with cmake */
#include <netinet/if_ether.h>
#include <netinet/in.h>

Expand All @@ -36,24 +38,75 @@
#include "tuntap.h"
#include "private.h"


#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include <sys/kern_event.h>

static int
tuntap_utun_open(char * ifname, uint32_t namesz)
{
int fd;
struct sockaddr_ctl addr;
struct ctl_info info;

if (-1 == (fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))) {
tuntap_log(TUNTAP_LOG_ERR, "utun is not supported");
return -1;
}

(void)memset(&info, 0, sizeof(info));
if (strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name)) \
>= sizeof(info.ctl_name)) {
tuntap_log(TUNTAP_LOG_ERR, "utun is not supported");
return -1;
}

if (ioctl(fd, CTLIOCGINFO, &info) < 0) {
tuntap_log(TUNTAP_LOG_ERR, "Can't retrieve kernel control id");
tuntap_log(TUNTAP_LOG_ERR, strerror(errno));
close(fd);
return -1;
}

addr.sc_id = info.ctl_id;
addr.sc_len = sizeof(addr);
addr.sc_family = AF_SYSTEM;
addr.ss_sysaddr = AF_SYS_CONTROL;
addr.sc_unit = 0; /* TODO: pass tun if not TUNTAP_ID_ANY */

if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
tuntap_log(TUNTAP_LOG_ERR, "utun interface probably already in use");
close(fd);
return -1;
}

if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, ifname, &namesz) < 0) {
tuntap_log(TUNTAP_LOG_ERR, "Can't retrieve utun name");
close(fd);
return -1;
}
return fd;
}

int
tuntap_sys_start(struct device *dev, int mode, int tun) {
struct ifreq ifr;
struct ifaddrs *ifa;
char name[MAXPATHLEN];
int fd;
char *type;
char *ifname;

fd = -1;

/* Force creation of the driver if needed or let it resilient */
if (mode & TUNTAP_MODE_PERSIST) {
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support persistent device");
tuntap_log(TUNTAP_LOG_NOTICE, "Your system does not support persistent device");
return -1;
}

/* Set the mode: tun or tap */
/* Set the mode: tun or tap */
if (mode == TUNTAP_MODE_ETHERNET) {
type = "tap";
ifr.ifr_flags |= IFF_LINK0;
Expand All @@ -67,17 +120,27 @@ tuntap_sys_start(struct device *dev, int mode, int tun) {
return -1;
}

ifname = NULL;

/* Try to use the given driver or loop throught the avaible ones */
if (tun < TUNTAP_ID_MAX) {
(void)snprintf(name, sizeof name, "/dev/%s%i", type, tun);
fd = open(name, O_RDWR);
} else if (tun == TUNTAP_ID_ANY) {
for (tun = 0; tun < TUNTAP_ID_MAX; ++tun) {
(void)memset(name, '\0', sizeof name);
(void)snprintf(name, sizeof name, "/dev/%s%i",
type, tun);
if ((fd = open(name, O_RDWR)) > 0)
break;
/* Use utun if we can */
if (mode == TUNTAP_MODE_TUNNEL) {
fd = tuntap_utun_open(name, IFNAMSIZ);
}
if (fd != -1)
ifname = name;
else {
for (tun = 0; tun < TUNTAP_ID_MAX; ++tun) {
(void)memset(name, '\0', sizeof name);
(void)snprintf(name, sizeof name, "/dev/%s%i",
type, tun);
if ((fd = open(name, O_RDWR)) > 0)
break;
}
}
} else {
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'tun'");
Expand All @@ -97,7 +160,14 @@ tuntap_sys_start(struct device *dev, int mode, int tun) {

/* Set the interface name */
(void)memset(&ifr, '\0', sizeof ifr);
(void)snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s%i", type, tun);
if (ifname) {
(void)strlcpy(ifr.ifr_name, ifname, \
strnlen(ifname, sizeof ifr.ifr_name));
} else {
(void)snprintf(ifr.ifr_name, sizeof ifr.ifr_name, \
"%s%i", type, tun);
}

/* And save it */
(void)strlcpy(dev->if_name, ifr.ifr_name, sizeof dev->if_name);

Expand Down