From d5efe1d64e977e76d38ec4f254396068d8a6cff1 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 22 Mar 2015 04:13:01 +0100 Subject: Rename tuntap to iface to match struct name --- src/CMakeLists.txt | 2 +- src/fastd.c | 4 +- src/fastd.h | 8 +- src/iface.c | 441 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/poll.c | 2 +- src/receive.c | 2 +- src/tuntap.c | 441 ----------------------------------------------------- 7 files changed, 450 insertions(+), 450 deletions(-) create mode 100644 src/iface.c delete mode 100644 src/tuntap.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e7dd5d1..dfcaf62 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(fastd handshake.c hkdf_sha256.c fastd.c + iface.c lex.c log.c options.c @@ -39,7 +40,6 @@ add_executable(fastd shell.c socket.c status.c - tuntap.c vector.c verify.c ${BISON_fastd_config_parse_OUTPUTS} diff --git a/src/fastd.c b/src/fastd.c index 228d65e..69efca5 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -526,7 +526,7 @@ static inline void init(int argc, char *argv[]) { on_pre_up(); - ctx.iface = fastd_tuntap_open(NULL); + ctx.iface = fastd_iface_open(NULL); /* change groups before trying to write the PID file as they can be relevant for file access */ set_groups(); @@ -647,7 +647,7 @@ static inline void cleanup(void) { delete_peers(); on_down(ctx.iface); - fastd_tuntap_close(ctx.iface); + fastd_iface_close(ctx.iface); fastd_status_close(); close_sockets(); diff --git a/src/fastd.h b/src/fastd.h index 5e81890..8704cc1 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -368,10 +368,10 @@ bool fastd_android_protect_socket(int fd); void fastd_resolve_peer(fastd_peer_t *peer, fastd_remote_t *remote); -fastd_iface_t * fastd_tuntap_open(fastd_peer_t *peer); -void fastd_tuntap_handle(fastd_iface_t *iface); -void fastd_tuntap_write(fastd_iface_t *iface, fastd_buffer_t buffer); -void fastd_tuntap_close(fastd_iface_t *iface); +fastd_iface_t * fastd_iface_open(fastd_peer_t *peer); +void fastd_iface_handle(fastd_iface_t *iface); +void fastd_iface_write(fastd_iface_t *iface, fastd_buffer_t buffer); +void fastd_iface_close(fastd_iface_t *iface); void fastd_cap_init(void); void fastd_cap_drop(void); diff --git a/src/iface.c b/src/iface.c new file mode 100644 index 0000000..b448cbd --- /dev/null +++ b/src/iface.c @@ -0,0 +1,441 @@ +/* + Copyright (c) 2012-2015, Matthias Schiffer + All rights reserved. + + Android port contributor: + Copyright (c) 2014-2015, Haofeng "Rick" Lei + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + \file + + Management of the TUN/TAP interface +*/ + +#include "fastd.h" +#include "poll.h" + +#include +#include + +#ifdef __linux__ + +#include + +#else + +#ifndef __APPLE__ +#include +#endif + +#ifdef __FreeBSD__ +#include +#endif + +#endif + + +/** Defines if the platform uses an address family header on TUN interfaces */ +#if defined(__linux__) || defined(__APPLE__) +static const bool multiaf_tun = false; +#else +static const bool multiaf_tun = true; +#endif + +#ifdef __linux__ + +/** Opens the TUN/TAP device helper shared by Android and Linux targets */ +static void open_iface_linux(fastd_iface_t *iface, const char *dev_name) { + struct ifreq ifr = {}; + + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(dev_name, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) + exit_errno("could not open tun/tap device file"); + + if (conf.ifname) + strncpy(ifr.ifr_name, conf.ifname, IFNAMSIZ-1); + + switch (conf.mode) { + case MODE_TAP: + ifr.ifr_flags = IFF_TAP; + break; + + case MODE_TUN: + ifr.ifr_flags = IFF_TUN; + break; + + default: + exit_bug("invalid mode"); + } + + ifr.ifr_flags |= IFF_NO_PI; + if (ioctl(iface->fd.fd, TUNSETIFF, &ifr) < 0) + exit_errno("TUNSETIFF ioctl failed"); + + iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); + + int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ctl_sock < 0) + exit_errno("socket"); + + if (ioctl(ctl_sock, SIOCGIFMTU, &ifr) < 0) + exit_errno("SIOCGIFMTU ioctl failed"); + + if (ifr.ifr_mtu != conf.mtu) { + ifr.ifr_mtu = conf.mtu; + if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0) + exit_errno("SIOCSIFMTU ioctl failed"); + } + + if (close(ctl_sock)) + pr_error_errno("close"); + +} + +#endif + +#if defined(__ANDROID__) + +/** Opens the TUN/TAP device */ +static void open_iface(fastd_iface_t *iface) { + if (conf.android_integration) { + if (conf.mode != MODE_TUN) + exit_error("Non root Android supports only TUN mode"); + + pr_debug("using android TUN fd"); + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, fastd_android_receive_tunfd()); + + fastd_android_send_pid(); + } else { + /* this requires root on Android */ + open_iface_linux(iface, "/dev/tun"); + } +} + +#elif defined(__linux__) + +/** Opens the TUN/TAP device */ +static void open_iface(fastd_iface_t *iface) { + open_iface_linux(iface, "/dev/net/tun"); +} + +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + +/** Sets the MTU of the TUN/TAP device */ +static void set_tun_mtu(fastd_iface_t *iface) { + struct tuninfo tuninfo; + + if (ioctl(iface->fd.fd, TUNGIFINFO, &tuninfo) < 0) + exit_errno("TUNGIFINFO ioctl failed"); + + tuninfo.mtu = conf.mtu; + + if (ioctl(iface->fd.fd, TUNSIFINFO, &tuninfo) < 0) + exit_errno("TUNSIFINFO ioctl failed"); +} + + +#ifdef __FreeBSD__ + +/** Sets the MTU of the TAP device */ +static void set_tap_mtu(fastd_iface_t *iface) { + struct tapinfo tapinfo; + + if (ioctl(iface->fd.fd, TAPGIFINFO, &tapinfo) < 0) + exit_errno("TAPGIFINFO ioctl failed"); + + tapinfo.mtu = conf.mtu; + + if (ioctl(iface->fd.fd, TAPSIFINFO, &tapinfo) < 0) + exit_errno("TAPSIFINFO ioctl failed"); +} + +/** Sets up the TUN device */ +static void setup_tun(fastd_iface_t *iface) { + int one = 1; + if (ioctl(iface->fd.fd, TUNSIFHEAD, &one) < 0) + exit_errno("TUNSIFHEAD ioctl failed"); + + set_tun_mtu(iface); +} + +/** Sets up the TAP device */ +static void setup_tap(fastd_iface_t *iface) { + struct ifreq ifr = {}; + + if (ioctl(iface->fd.fd, TAPGIFNAME, &ifr) < 0) + exit_errno("TAPGIFNAME ioctl failed"); + + free(iface->name); + iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); + + set_tap_mtu(iface); +} + +/** Opens the TUN/TAP device */ +static void open_iface(fastd_iface_t *iface) { + char ifname[5+IFNAMSIZ] = "/dev/"; + const char *type; + + switch (conf.mode) { + case MODE_TAP: + type = "tap"; + break; + + case MODE_TUN: + type = "tun"; + break; + + default: + exit_bug("invalid mode"); + } + + if (conf.ifname) { + if (strncmp(conf.ifname, type, 3) != 0) + exit_error("`%s' doesn't seem to be a %s device", conf.ifname, type); + + strncat(ifname, conf.ifname, IFNAMSIZ-1); + } + else { + strncat(ifname, type, IFNAMSIZ-1); + } + + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) + exit_errno("could not open tun/tap device file"); + + if (!(iface->name = fdevname_r(iface->fd.fd, fastd_alloc(IFNAMSIZ), IFNAMSIZ))) + exit_errno("could not get tun/tap interface name"); + + switch (conf.mode) { + case MODE_TAP: + setup_tap(iface); + break; + + case MODE_TUN: + setup_tun(iface); + break; + + default: + exit_bug("invalid mode"); + } +} + +#else /* __OpenBSD__ */ + +static void set_link0(fastd_iface_t *iface, bool set) { + struct ifreq ifr = {}; + + int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ctl_sock < 0) + exit_errno("socket"); + + strncpy(ifr.ifr_name, iface->name, IFNAMSIZ-1); + if (ioctl(ctl_sock, SIOCGIFFLAGS, &ifr) < 0) + exit_errno("SIOCGIFFLAGS ioctl failed"); + + if (set) + ifr.ifr_flags |= IFF_LINK0; + else + ifr.ifr_flags &= ~IFF_LINK0; + + if (ioctl(ctl_sock, SIOCSIFFLAGS, &ifr) < 0) + exit_errno("SIOCSIFFLAGS ioctl failed"); + + if (close(ctl_sock)) + pr_error_errno("close"); +} + +/** Sets up the TUN device */ +static void setup_tun(fastd_iface_t *iface) { + set_link0(iface, false); + set_tun_mtu(iface); +} + +/** Sets up the TAP device */ +static void setup_tap(fastd_iface_t *iface) { + set_link0(iface, true); + set_tun_mtu(iface); +} + +/** Opens the TUN/TAP device */ +static void open_iface(fastd_iface_t *iface) { + char ifname[5+IFNAMSIZ] = "/dev/"; + if (!conf.ifname) + exit_error("config error: no interface name given."); + else if (strncmp(conf.ifname, "tun", 3) != 0) + exit_error("config error: `%s' doesn't seem to be a tun device", conf.ifname); + else + strncat(ifname, conf.ifname, IFNAMSIZ-1); + + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) + exit_errno("could not open tun device file"); + + iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); + + switch (conf.mode) { + case MODE_TAP: + setup_tap(iface); + break; + + case MODE_TUN: + setup_tun(iface); + break; + + default: + exit_bug("invalid mode"); + } +} + +#endif + +#elif __APPLE__ + +/** Opens the TUN/TAP device */ +static void open_iface(fastd_iface_t *iface) { + const char *devtype; + switch (conf.mode) { + case MODE_TAP: + devtype = "tap"; + break; + + case MODE_TUN: + devtype = "tun"; + break; + + default: + exit_bug("invalid mode"); + } + + char ifname[5+IFNAMSIZ] = "/dev/"; + if (!conf.ifname) + exit_error("config error: no interface name given."); + else if (strncmp(conf.ifname, devtype, 3) != 0) + exit_error("config error: `%s' doesn't seem to be a %s device", conf.ifname, devtype); + else + strncat(ifname, conf.ifname, IFNAMSIZ-1); + + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) + exit_errno("could not open tun device file"); + + iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); + + int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ctl_sock < 0) + exit_errno("socket"); + + struct ifreq ifr = {}; + strncpy(ifr.ifr_name, conf.ifname, IFNAMSIZ-1); + ifr.ifr_mtu = conf.mtu; + if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0) + exit_errno("SIOCSIFMTU ioctl failed"); + + if (close(ctl_sock)) + pr_error_errno("close"); +} + +#else + +#error unknown tun/tap implementation + +#endif + + +/** Reads a packet from the TUN/TAP device */ +void fastd_iface_handle(fastd_iface_t *iface) { + size_t max_len = fastd_max_payload(); + + fastd_buffer_t buffer; + if (multiaf_tun && conf.mode == MODE_TUN) + buffer = fastd_buffer_alloc(max_len+4, conf.min_encrypt_head_space+12, conf.min_encrypt_tail_space); + else + buffer = fastd_buffer_alloc(max_len, conf.min_encrypt_head_space, conf.min_encrypt_tail_space); + + ssize_t len = read(iface->fd.fd, buffer.data, max_len); + if (len < 0) + exit_errno("read"); + + buffer.len = len; + + if (multiaf_tun && conf.mode == MODE_TUN) + fastd_buffer_push_head(&buffer, 4); + + fastd_send_data(buffer, iface->peer); +} + +/** Writes a packet to the TUN/TAP device */ +void fastd_iface_write(fastd_iface_t *iface, fastd_buffer_t buffer) { + if (multiaf_tun && conf.mode == MODE_TUN) { + uint8_t version = *((uint8_t *)buffer.data) >> 4; + uint32_t af; + + switch (version) { + case 4: + af = htonl(AF_INET); + break; + + case 6: + af = htonl(AF_INET6); + break; + + default: + pr_warn("fastd_iface_write: unknown IP version %u", version); + return; + } + + fastd_buffer_pull_head(&buffer, 4); + memcpy(buffer.data, &af, 4); + } + + if (write(iface->fd.fd, buffer.data, buffer.len) < 0) + pr_debug2_errno("write"); +} + +fastd_iface_t * fastd_iface_open(fastd_peer_t *peer) { + fastd_iface_t *iface = fastd_new(fastd_iface_t); + iface->peer = peer; + + pr_debug("initializing tun/tap device..."); + open_iface(iface); + + if (iface->name) + pr_debug("tun/tap device `%s' initialized.", iface->name); + else + pr_debug("tun/tap device initialized."); + + fastd_poll_fd_register(&iface->fd); + + return iface; +} + +/** Closes the TUN/TAP device */ +void fastd_iface_close(fastd_iface_t *iface) { + if (!fastd_poll_fd_close(&iface->fd)) + pr_warn_errno("closing tun/tap: close"); + + free(iface->name); + free(iface); +} diff --git a/src/poll.c b/src/poll.c index dbb3c18..2ae6867 100644 --- a/src/poll.c +++ b/src/poll.c @@ -86,7 +86,7 @@ static inline void handle_fd(fastd_poll_fd_t *fd, bool input, bool error) { fastd_iface_t *iface = container_of(fd, fastd_iface_t, fd); if (input) - fastd_tuntap_handle(iface); + fastd_iface_handle(iface); } break; diff --git a/src/receive.c b/src/receive.c index a19039e..2f0c87c 100644 --- a/src/receive.c +++ b/src/receive.c @@ -306,7 +306,7 @@ void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer, bool reorde if (reordered) fastd_stats_add(peer, STAT_RX_REORDERED, buffer.len); - fastd_tuntap_write(peer->iface ?: ctx.iface, buffer); + fastd_iface_write(peer->iface ?: ctx.iface, buffer); if (conf.mode == MODE_TAP && conf.forward) { fastd_send_data(buffer, peer); diff --git a/src/tuntap.c b/src/tuntap.c deleted file mode 100644 index a817090..0000000 --- a/src/tuntap.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - Copyright (c) 2012-2015, Matthias Schiffer - All rights reserved. - - Android port contributor: - Copyright (c) 2014-2015, Haofeng "Rick" Lei - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - \file - - Management of the TUN/TAP interface -*/ - -#include "fastd.h" -#include "poll.h" - -#include -#include - -#ifdef __linux__ - -#include - -#else - -#ifndef __APPLE__ -#include -#endif - -#ifdef __FreeBSD__ -#include -#endif - -#endif - - -/** Defines if the platform uses an address family header on TUN interfaces */ -#if defined(__linux__) || defined(__APPLE__) -static const bool multiaf_tun = false; -#else -static const bool multiaf_tun = true; -#endif - -#ifdef __linux__ - -/** Opens the TUN/TAP device helper shared by Android and Linux targets */ -static void tuntap_open_linux(fastd_iface_t *iface, const char *dev_name) { - struct ifreq ifr = {}; - - iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(dev_name, O_RDWR|O_NONBLOCK)); - if (iface->fd.fd < 0) - exit_errno("could not open tun/tap device file"); - - if (conf.ifname) - strncpy(ifr.ifr_name, conf.ifname, IFNAMSIZ-1); - - switch (conf.mode) { - case MODE_TAP: - ifr.ifr_flags = IFF_TAP; - break; - - case MODE_TUN: - ifr.ifr_flags = IFF_TUN; - break; - - default: - exit_bug("invalid mode"); - } - - ifr.ifr_flags |= IFF_NO_PI; - if (ioctl(iface->fd.fd, TUNSETIFF, &ifr) < 0) - exit_errno("TUNSETIFF ioctl failed"); - - iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); - - int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (ctl_sock < 0) - exit_errno("socket"); - - if (ioctl(ctl_sock, SIOCGIFMTU, &ifr) < 0) - exit_errno("SIOCGIFMTU ioctl failed"); - - if (ifr.ifr_mtu != conf.mtu) { - ifr.ifr_mtu = conf.mtu; - if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0) - exit_errno("SIOCSIFMTU ioctl failed"); - } - - if (close(ctl_sock)) - pr_error_errno("close"); - -} - -#endif - -#if defined(__ANDROID__) - -/** Opens the TUN/TAP device */ -static void tuntap_open(fastd_iface_t *iface) { - if (conf.android_integration) { - if (conf.mode != MODE_TUN) - exit_error("Non root Android supports only TUN mode"); - - pr_debug("using android TUN fd"); - iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, fastd_android_receive_tunfd()); - - fastd_android_send_pid(); - } else { - /* this requires root on Android */ - tuntap_open_linux(iface, "/dev/tun"); - } -} - -#elif defined(__linux__) - -/** Opens the TUN/TAP device */ -static void tuntap_open(fastd_iface_t *iface) { - tuntap_open_linux(iface, "/dev/net/tun"); -} - -#elif defined(__FreeBSD__) || defined(__OpenBSD__) - -/** Sets the MTU of the TUN/TAP device */ -static void set_tun_mtu(fastd_iface_t *iface) { - struct tuninfo tuninfo; - - if (ioctl(iface->fd.fd, TUNGIFINFO, &tuninfo) < 0) - exit_errno("TUNGIFINFO ioctl failed"); - - tuninfo.mtu = conf.mtu; - - if (ioctl(iface->fd.fd, TUNSIFINFO, &tuninfo) < 0) - exit_errno("TUNSIFINFO ioctl failed"); -} - - -#ifdef __FreeBSD__ - -/** Sets the MTU of the TAP device */ -static void set_tap_mtu(fastd_iface_t *iface) { - struct tapinfo tapinfo; - - if (ioctl(iface->fd.fd, TAPGIFINFO, &tapinfo) < 0) - exit_errno("TAPGIFINFO ioctl failed"); - - tapinfo.mtu = conf.mtu; - - if (ioctl(iface->fd.fd, TAPSIFINFO, &tapinfo) < 0) - exit_errno("TAPSIFINFO ioctl failed"); -} - -/** Sets up the TUN device */ -static void setup_tun(fastd_iface_t *iface) { - int one = 1; - if (ioctl(iface->fd.fd, TUNSIFHEAD, &one) < 0) - exit_errno("TUNSIFHEAD ioctl failed"); - - set_tun_mtu(iface); -} - -/** Sets up the TAP device */ -static void setup_tap(fastd_iface_t *iface) { - struct ifreq ifr = {}; - - if (ioctl(iface->fd.fd, TAPGIFNAME, &ifr) < 0) - exit_errno("TAPGIFNAME ioctl failed"); - - free(iface->name); - iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); - - set_tap_mtu(iface); -} - -/** Opens the TUN/TAP device */ -static void tuntap_open(fastd_iface_t *iface) { - char ifname[5+IFNAMSIZ] = "/dev/"; - const char *type; - - switch (conf.mode) { - case MODE_TAP: - type = "tap"; - break; - - case MODE_TUN: - type = "tun"; - break; - - default: - exit_bug("invalid mode"); - } - - if (conf.ifname) { - if (strncmp(conf.ifname, type, 3) != 0) - exit_error("`%s' doesn't seem to be a %s device", conf.ifname, type); - - strncat(ifname, conf.ifname, IFNAMSIZ-1); - } - else { - strncat(ifname, type, IFNAMSIZ-1); - } - - iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (iface->fd.fd < 0) - exit_errno("could not open tun/tap device file"); - - if (!(iface->name = fdevname_r(iface->fd.fd, fastd_alloc(IFNAMSIZ), IFNAMSIZ))) - exit_errno("could not get tun/tap interface name"); - - switch (conf.mode) { - case MODE_TAP: - setup_tap(iface); - break; - - case MODE_TUN: - setup_tun(iface); - break; - - default: - exit_bug("invalid mode"); - } -} - -#else /* __OpenBSD__ */ - -static void set_link0(fastd_iface_t *iface, bool set) { - struct ifreq ifr = {}; - - int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (ctl_sock < 0) - exit_errno("socket"); - - strncpy(ifr.ifr_name, iface->name, IFNAMSIZ-1); - if (ioctl(ctl_sock, SIOCGIFFLAGS, &ifr) < 0) - exit_errno("SIOCGIFFLAGS ioctl failed"); - - if (set) - ifr.ifr_flags |= IFF_LINK0; - else - ifr.ifr_flags &= ~IFF_LINK0; - - if (ioctl(ctl_sock, SIOCSIFFLAGS, &ifr) < 0) - exit_errno("SIOCSIFFLAGS ioctl failed"); - - if (close(ctl_sock)) - pr_error_errno("close"); -} - -/** Sets up the TUN device */ -static void setup_tun(fastd_iface_t *iface) { - set_link0(iface, false); - set_tun_mtu(iface); -} - -/** Sets up the TAP device */ -static void setup_tap(fastd_iface_t *iface) { - set_link0(iface, true); - set_tun_mtu(iface); -} - -/** Opens the TUN/TAP device */ -static void tuntap_open(fastd_iface_t *iface) { - char ifname[5+IFNAMSIZ] = "/dev/"; - if (!conf.ifname) - exit_error("config error: no interface name given."); - else if (strncmp(conf.ifname, "tun", 3) != 0) - exit_error("config error: `%s' doesn't seem to be a tun device", conf.ifname); - else - strncat(ifname, conf.ifname, IFNAMSIZ-1); - - iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (iface->fd.fd < 0) - exit_errno("could not open tun device file"); - - iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); - - switch (conf.mode) { - case MODE_TAP: - setup_tap(iface); - break; - - case MODE_TUN: - setup_tun(iface); - break; - - default: - exit_bug("invalid mode"); - } -} - -#endif - -#elif __APPLE__ - -/** Opens the TUN/TAP device */ -static void tuntap_open(fastd_iface_t *iface) { - const char *devtype; - switch (conf.mode) { - case MODE_TAP: - devtype = "tap"; - break; - - case MODE_TUN: - devtype = "tun"; - break; - - default: - exit_bug("invalid mode"); - } - - char ifname[5+IFNAMSIZ] = "/dev/"; - if (!conf.ifname) - exit_error("config error: no interface name given."); - else if (strncmp(conf.ifname, devtype, 3) != 0) - exit_error("config error: `%s' doesn't seem to be a %s device", conf.ifname, devtype); - else - strncat(ifname, conf.ifname, IFNAMSIZ-1); - - iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (iface->fd.fd < 0) - exit_errno("could not open tun device file"); - - iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); - - int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (ctl_sock < 0) - exit_errno("socket"); - - struct ifreq ifr = {}; - strncpy(ifr.ifr_name, conf.ifname, IFNAMSIZ-1); - ifr.ifr_mtu = conf.mtu; - if (ioctl(ctl_sock, SIOCSIFMTU, &ifr) < 0) - exit_errno("SIOCSIFMTU ioctl failed"); - - if (close(ctl_sock)) - pr_error_errno("close"); -} - -#else - -#error unknown tun/tap implementation - -#endif - - -/** Reads a packet from the TUN/TAP device */ -void fastd_tuntap_handle(fastd_iface_t *iface) { - size_t max_len = fastd_max_payload(); - - fastd_buffer_t buffer; - if (multiaf_tun && conf.mode == MODE_TUN) - buffer = fastd_buffer_alloc(max_len+4, conf.min_encrypt_head_space+12, conf.min_encrypt_tail_space); - else - buffer = fastd_buffer_alloc(max_len, conf.min_encrypt_head_space, conf.min_encrypt_tail_space); - - ssize_t len = read(iface->fd.fd, buffer.data, max_len); - if (len < 0) - exit_errno("read"); - - buffer.len = len; - - if (multiaf_tun && conf.mode == MODE_TUN) - fastd_buffer_push_head(&buffer, 4); - - fastd_send_data(buffer, iface->peer); -} - -/** Writes a packet to the TUN/TAP device */ -void fastd_tuntap_write(fastd_iface_t *iface, fastd_buffer_t buffer) { - if (multiaf_tun && conf.mode == MODE_TUN) { - uint8_t version = *((uint8_t *)buffer.data) >> 4; - uint32_t af; - - switch (version) { - case 4: - af = htonl(AF_INET); - break; - - case 6: - af = htonl(AF_INET6); - break; - - default: - pr_warn("fastd_tuntap_write: unknown IP version %u", version); - return; - } - - fastd_buffer_pull_head(&buffer, 4); - memcpy(buffer.data, &af, 4); - } - - if (write(iface->fd.fd, buffer.data, buffer.len) < 0) - pr_debug2_errno("write"); -} - -fastd_iface_t * fastd_tuntap_open(fastd_peer_t *peer) { - fastd_iface_t *iface = fastd_new(fastd_iface_t); - iface->peer = peer; - - pr_debug("initializing tun/tap device..."); - tuntap_open(iface); - - if (iface->name) - pr_debug("tun/tap device `%s' initialized.", iface->name); - else - pr_debug("tun/tap device initialized."); - - fastd_poll_fd_register(&iface->fd); - - return iface; -} - -/** Closes the TUN/TAP device */ -void fastd_tuntap_close(fastd_iface_t *iface) { - if (!fastd_poll_fd_close(&iface->fd)) - pr_warn_errno("closing tun/tap: close"); - - free(iface->name); - free(iface); -} -- cgit v1.2.3