diff options
Diffstat (limited to 'src/libstrongswan/utils/tun_device.c')
-rw-r--r-- | src/libstrongswan/utils/tun_device.c | 461 |
1 files changed, 0 insertions, 461 deletions
diff --git a/src/libstrongswan/utils/tun_device.c b/src/libstrongswan/utils/tun_device.c deleted file mode 100644 index 36f3359c0..000000000 --- a/src/libstrongswan/utils/tun_device.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * 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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <errno.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <unistd.h> -#include <net/if.h> - -#ifdef __APPLE__ -#include <net/if_utun.h> -#include <netinet/in_var.h> -#include <sys/kern_control.h> -#elif defined(__linux__) -#include <linux/if_tun.h> -#else -#include <net/if_tun.h> -#endif - -#include "tun_device.h" - -#include <library.h> -#include <debug.h> -#include <threading/thread.h> - -#define TUN_DEFAULT_MTU 1500 - -typedef struct private_tun_device_t private_tun_device_t; - -struct private_tun_device_t { - - /** - * Public interface - */ - tun_device_t public; - - /** - * The TUN device's file descriptor - */ - int tunfd; - - /** - * Name of the TUN device - */ - char if_name[IFNAMSIZ]; - - /** - * Socket used for ioctl() to set interface addr, ... - */ - int sock; - - /** - * The current MTU - */ - int mtu; -}; - -/** - * Set the sockaddr_t from the given netmask - */ -static void set_netmask(struct ifreq *ifr, int family, u_int8_t netmask) -{ - int len, bytes, bits; - char *target; - - switch (family) - { - case AF_INET: - { - struct sockaddr_in *addr = (struct sockaddr_in*)&ifr->ifr_addr; - addr->sin_family = AF_INET; - target = (char*)&addr->sin_addr; - len = 4; - break; - } - case AF_INET6: - { - struct sockaddr_in6 *addr = (struct sockaddr_in6*)&ifr->ifr_addr; - addr->sin6_family = AF_INET6; - target = (char*)&addr->sin6_addr; - len = 16; - break; - } - default: - return; - } - - bytes = (netmask + 7) / 8; - bits = (bytes * 8) - netmask; - - memset(target, 0xff, bytes); - memset(target + bytes, 0x00, len - bytes); - target[bytes - 1] = bits ? (u_int8_t)(0xff << bits) : 0xff; -} - -METHOD(tun_device_t, set_address, bool, - private_tun_device_t *this, host_t *addr, u_int8_t netmask) -{ - struct ifreq ifr; - int family; - - family = addr->get_family(addr); - if ((netmask > 32 && family == AF_INET) || netmask > 128) - { - DBG1(DBG_LIB, "failed to set address on %s: invalid netmask", - this->if_name); - return FALSE; - } - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - memcpy(&ifr.ifr_addr, addr->get_sockaddr(addr), sizeof(sockaddr_t)); - - if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set address on %s: %s", - 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); - - if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set netmask on %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, up, bool, - private_tun_device_t *this) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - - if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - - ifr.ifr_flags |= IFF_RUNNING | IFF_UP; - - if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, set_mtu, bool, - private_tun_device_t *this, int mtu) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - ifr.ifr_mtu = mtu; - - if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - this->mtu = mtu; - return TRUE; -} - -METHOD(tun_device_t, get_mtu, int, - private_tun_device_t *this) -{ - struct ifreq ifr; - - if (this->mtu > 0) - { - return this->mtu; - } - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - this->mtu = TUN_DEFAULT_MTU; - - if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0) - { - this->mtu = ifr.ifr_mtu; - } - return this->mtu; -} - -METHOD(tun_device_t, get_name, char*, - private_tun_device_t *this) -{ - return this->if_name; -} - -METHOD(tun_device_t, write_packet, bool, - private_tun_device_t *this, chunk_t packet) -{ - ssize_t s; - - s = write(this->tunfd, packet.ptr, packet.len); - if (s < 0) - { - DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } - else if (s != packet.len) - { - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, read_packet, bool, - private_tun_device_t *this, chunk_t *packet) -{ - ssize_t len; - fd_set set; - bool old; - - FD_ZERO(&set); - FD_SET(this->tunfd, &set); - - old = thread_cancelability(TRUE); - len = select(this->tunfd + 1, &set, NULL, NULL, NULL); - thread_cancelability(old); - - if (len < 0) - { - DBG1(DBG_LIB, "select on TUN device %s failed: %s", this->if_name, - strerror(errno)); - return FALSE; - } - /* FIXME: this is quite expensive for lots of small packets, copy from - * local buffer instead? */ - *packet = chunk_alloc(get_mtu(this)); - len = read(this->tunfd, packet->ptr, packet->len); - if (len < 0) - { - DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name, - strerror(errno)); - chunk_free(packet); - return FALSE; - } - packet->len = len; - return TRUE; -} - -METHOD(tun_device_t, destroy, void, - private_tun_device_t *this) -{ - if (this->tunfd > 0) - { - close(this->tunfd); -#ifdef __FreeBSD__ - /* tun(4) says the following: "These network interfaces persist until - * the if_tun.ko module is unloaded, or until removed with the - * ifconfig(8) command." So simply closing the FD is not enough. */ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name, - strerror(errno)); - } -#endif /* __FreeBSD__ */ - } - if (this->sock > 0) - { - close(this->sock); - } - free(this); -} - -/** - * Initialize the tun device - */ -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; - -#elif defined(IFF_TUN) - - struct ifreq ifr; - - 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 FALSE; - } - - memset(&ifr, 0, sizeof(ifr)); - - /* TUN device, no packet info */ - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - - 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(this->tunfd); - return FALSE; - } - strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ); - return TRUE; - -#else /* !IFF_TUN */ - - /* this works on FreeBSD and might also work on Linux with older TUN - * driver versions (no IFF_TUN) */ - char devname[IFNAMSIZ]; - int i; - - if (name_tmpl) - { - DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported"); - } - - for (i = 0; i < 256; i++) - { - snprintf(devname, IFNAMSIZ, "/dev/tun%d", i); - this->tunfd = open(devname, O_RDWR); - if (this->tunfd > 0) - { /* for ioctl(2) calls only the interface name is used */ - snprintf(this->if_name, IFNAMSIZ, "tun%d", i); - break; - } - DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno)); - } - return this->tunfd > 0; - -#endif /* !__APPLE__ */ -} - -/* - * Described in header - */ -tun_device_t *tun_device_create(const char *name_tmpl) -{ - private_tun_device_t *this; - - INIT(this, - .public = { - .read_packet = _read_packet, - .write_packet = _write_packet, - .get_mtu = _get_mtu, - .set_mtu = _set_mtu, - .get_name = _get_name, - .set_address = _set_address, - .up = _up, - .destroy = _destroy, - }, - .tunfd = -1, - .sock = -1, - ); - - if (!init_tun(this, name_tmpl)) - { - free(this); - return NULL; - } - DBG1(DBG_LIB, "created TUN device: %s", this->if_name); - - this->sock = socket(AF_INET, SOCK_DGRAM, 0); - if (this->sock < 0) - { - DBG1(DBG_LIB, "failed to open socket to configure TUN device"); - destroy(this); - return NULL; - } - return &this->public; -} |