From c046a1f8030c4f0ada9ab860afc433423bb4bac8 Mon Sep 17 00:00:00 2001 From: Sebastien Vincent Date: Wed, 16 Aug 2017 01:02:40 +0200 Subject: [PATCH] Adds support to use existing TAP interfaces on POSIX systems. (#153) * Fixes some doxygen comments. * Adds the possibility to use an existing TUN/TAP interface for POSIX systems. * Be sure to not set interface UP/DOWN if not root and if using existing TUN/TAP interface. * Adds some notes in configuration file regarding use of fscp.name parameter on POSIX systems. Also do not destroy tap interface on macOS/BSD if fscp.name is specified. * Adds precisions in freelan.cfg file about using existing TAP interface. Minor tweaks in POSIX asiotap with existing interface. --- apps/freelan/config/freelan.cfg | 11 +++++-- .../asiotap/posix/posix_tap_adapter.hpp | 5 ++++ libs/asiotap/src/posix/posix_tap_adapter.cpp | 30 ++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/apps/freelan/config/freelan.cfg b/apps/freelan/config/freelan.cfg index 792ca174..f0c4785e 100644 --- a/apps/freelan/config/freelan.cfg +++ b/apps/freelan/config/freelan.cfg @@ -370,9 +370,14 @@ public_endpoint=0.0.0.0 # If no name or an empty name is provided, the first available adapter will be # used. # -# On UNIX, it is the name of the tap adapter to create. Depending on your -# system, some names might be restricted, and something in the form of tapX -# (where X is a positive number) is recommended. +# On POSIX systems, it is the name of the tap adapter to create or to use. +# Depending on your system, some names might be restricted, and something in the +# form of tapX (where X is a positive number) is recommended. +# +# If you use an existing interface and run as non-root, the interface name MUST +# exist, belong to the user, be UP and already has IP configuration or use DHCP. +# Additionnaly on Linux, user MUST have read-write permissions on /dev/net/tap +# or /dev/net/tun (depending on which mode is used). # # If no name or an empty name is provided, a tap adapter will be created with # an available name. diff --git a/libs/asiotap/include/asiotap/posix/posix_tap_adapter.hpp b/libs/asiotap/include/asiotap/posix/posix_tap_adapter.hpp index 793a5ac5..61c23e85 100644 --- a/libs/asiotap/include/asiotap/posix/posix_tap_adapter.hpp +++ b/libs/asiotap/include/asiotap/posix/posix_tap_adapter.hpp @@ -203,6 +203,11 @@ namespace asiotap void destroy_device(boost::system::error_code& ec); posix_route_manager m_route_manager; + + /** + * \brief If we use an existing tun/tap adapter. + */ + bool m_existing_tap; }; } diff --git a/libs/asiotap/src/posix/posix_tap_adapter.cpp b/libs/asiotap/src/posix/posix_tap_adapter.cpp index d98d7361..08487ca9 100644 --- a/libs/asiotap/src/posix/posix_tap_adapter.cpp +++ b/libs/asiotap/src/posix/posix_tap_adapter.cpp @@ -57,6 +57,7 @@ #include #include + /** * \struct in6_ifreq * \brief Replacement structure since the include of linux/ipv6.h introduces conflicts. @@ -234,6 +235,8 @@ namespace asiotap { ec = boost::system::error_code(); + m_existing_tap = !_name.empty(); + #if defined(LINUX) const std::string dev_name = (layer() == tap_adapter_layer::ethernet) ? "/dev/net/tap" : "/dev/net/tun"; @@ -241,13 +244,13 @@ namespace asiotap { if (errno != ENOENT) { - // Unable to access the tap adapter yet it exists: this is an error. + // Unable to access the tap adapter yet it exists: this is an error. ec = boost::system::error_code(errno, boost::system::system_category()); return; } - // No tap found, create one. + // No tap found, create one. if (::mknod(dev_name.c_str(), S_IFCHR | S_IRUSR | S_IWUSR, ::makedev(10, 200)) == -1) { ec = boost::system::error_code(errno, boost::system::system_category()); @@ -309,7 +312,7 @@ namespace asiotap netifr.ifr_qlen = 100; // 100 is the default value - if (::ioctl(socket.native_handle(), SIOCSIFTXQLEN, (void *)&netifr) < 0) + if (getuid() == 0 && ::ioctl(socket.native_handle(), SIOCSIFTXQLEN, (void *)&netifr) < 0) { ec = boost::system::error_code(errno, boost::system::system_category()); @@ -484,6 +487,12 @@ namespace asiotap void posix_tap_adapter::destroy_device(boost::system::error_code& ec) { + // do not attempt to destroy interface if non-root + if(getuid() != 0) + { + return; + } + #if defined(MACINTOSH) || defined(BSD) descriptor_handler socket = open_socket(AF_INET, ec); @@ -514,12 +523,18 @@ namespace asiotap strncpy(netifr.ifr_name, name().c_str(), IFNAMSIZ); - // Set the interface UP + // Get the interface flags if (::ioctl(socket.native_handle(), SIOCGIFFLAGS, static_cast(&netifr)) < 0) { throw boost::system::system_error(errno, boost::system::system_category()); } + // as non-root, assume that existing TAP is correctly configured + if (getuid() != 0 && m_existing_tap) + { + return; + } + if (connected) { #ifdef MACINTOSH @@ -539,6 +554,7 @@ namespace asiotap #endif } + // Set the interface UP if (::ioctl(socket.native_handle(), SIOCSIFFLAGS, static_cast(&netifr)) < 0) { throw boost::system::system_error(errno, boost::system::system_category()); @@ -612,6 +628,12 @@ namespace asiotap void posix_tap_adapter::configure(const configuration_type& configuration) { + // as non-root, assume that existing TAP is correctly configured + if(getuid() != 0 && m_existing_tap) + { + return; + } + if (configuration.ipv4.network_address) { if (layer() == tap_adapter_layer::ethernet)