* Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012 Martin Willi
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
+
+#ifdef __APPLE__
+#include <net/if.h>
+#include <net/if_utun.h>
+#include <netinet/in_var.h>
+#include <sys/kern_control.h>
+#else /* !__APPLE__ */
#include <linux/if.h>
#include <linux/if_tun.h>
+#endif /* !__APPLE__ */
#include "tun_device.h"
this->if_name, strerror(errno));
return FALSE;
}
+#ifdef __APPLE__
+ if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0)
+ {
+ DBG1(DBG_LIB, "failed to set dest address on %s: %s",
+ this->if_name, strerror(errno));
+ return FALSE;
+ }
+#endif /* __APPLE__ */
set_netmask(&ifr, family, netmask);
}
/**
- * Allocate a TUN device
+ * Initialize the tun device
*/
-static int tun_alloc(char dev[IFNAMSIZ])
+static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
{
+#ifdef __APPLE__
+
+ struct ctl_info info;
+ struct sockaddr_ctl addr;
+ socklen_t size = IFNAMSIZ;
+
+ memset(&info, 0, sizeof(info));
+ memset(&addr, 0, sizeof(addr));
+
+ this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (this->tunfd < 0)
+ {
+ DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s",
+ strerror(errno));
+ return FALSE;
+ }
+
+ /* get a control identifier for the utun kernel extension */
+ strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
+ if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0)
+ {
+ DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+
+ addr.sc_id = info.ctl_id;
+ addr.sc_len = sizeof(addr);
+ addr.sc_family = AF_SYSTEM;
+ addr.ss_sysaddr = AF_SYS_CONTROL;
+ /* allocate identifier dynamically */
+ addr.sc_unit = 0;
+
+ if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
+ {
+ DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+ if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
+ this->if_name, &size) < 0)
+ {
+ DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno));
+ close(this->tunfd);
+ return FALSE;
+ }
+ return TRUE;
+
+#else /* !__APPLE__ */
+
struct ifreq ifr;
- int fd;
- fd = open("/dev/net/tun", O_RDWR);
- if (fd < 0)
+ strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
+ this->if_name[IFNAMSIZ-1] = '\0';
+
+ this->tunfd = open("/dev/net/tun", O_RDWR);
+ if (this->tunfd < 0)
{
DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno));
- return fd;
+ return FALSE;
}
memset(&ifr, 0, sizeof(ifr));
/* TUN device, no packet info */
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-
- if (ioctl(fd, TUNSETIFF, (void*)&ifr) < 0)
+ strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
+ if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0)
{
DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno));
- close(fd);
- return -1;
+ close(this->tunfd);
+ return FALSE;
}
- strncpy(dev, ifr.ifr_name, IFNAMSIZ);
- return fd;
+ strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
+ return TRUE;
+
+#endif /* !__APPLE__ */
}
/*
.sock = -1,
);
- strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
- this->if_name[IFNAMSIZ-1] = '\0';
-
- this->tunfd = tun_alloc(this->if_name);
- if (this->tunfd < 0)
+ if (!init_tun(this, name_tmpl))
{
- destroy(this);
+ free(this);
return NULL;
}
DBG1(DBG_LIB, "created TUN device: %s", this->if_name);