diff --git a/NEWS.rst b/NEWS.rst index 23d8fee..d79c0b2 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -6,12 +6,15 @@ every change, see the Git log. Latest ------ -* tbd +* Major: Merged the tun_interface and tap_interface classes into a single + class called interface. The interface class can now create both TUN and TAP + interfaces based on the interface_type parameter provided to the create methods + config argument. 15.0.0 ------ -* Minor: Add initial macos/Darwin support. -* Major: change interface from seperate args to a struct +* Minor: Add initial macos/Darwin support. +* Major: Change interface from seperate args to a struct 14.1.1 ------ diff --git a/README.rst b/README.rst index b274087..1253960 100644 --- a/README.rst +++ b/README.rst @@ -22,8 +22,9 @@ tunnel .. |Cppcheck| image:: https://github.com/steinwurf/tunnel/actions/workflows/cppcheck.yml/badge.svg :target: https://github.com/steinwurf/tunnel/actions/workflows/cppcheck.yml -The tunnel lib allows you to create and manipulate TUN interfaces on Linux. +The tunnel lib allows you to create and manipulate TUN and TAP interfaces on Linux and MacOS. A tun interface is essentially a virtual network interface on the IP (layer 3). +A tap interface is essentially a virtual network interface on the Ethernet (layer 2). .. contents:: Table of Contents: diff --git a/apps/app/tunnel.cpp b/apps/app/tunnel.cpp index 868be10..1f79392 100644 --- a/apps/app/tunnel.cpp +++ b/apps/app/tunnel.cpp @@ -8,12 +8,11 @@ #include #include #include -#include -#include +#include #if defined(PLATFORM_LINUX) #include -inline void enable_core_dumps() +void enable_core_dumps() { // core dumps may be disallowed by the parent of this process; change that struct rlimit core_limits; @@ -21,69 +20,36 @@ inline void enable_core_dumps() setrlimit(RLIMIT_CORE, &core_limits); } #else -inline void enable_core_dumps() +void enable_core_dumps() { // do nothing } #endif -inline auto parse_ip(const std::string& address) -> asio::ip::address +auto to_endpoint(const std::string& endpoint_str) -> asio::ip::udp::endpoint { - // If there is a port - std::size_t found = address.rfind(':'); - - if (found != std::string::npos) - { - - // Make address and check if it is valid - asio::error_code ec; - asio::ip::address addr = - asio::ip::make_address(address.substr(0, found), ec); - if (ec) - { - throw std::runtime_error("Invalid address: " + address); - } - return addr; - } - else + std::size_t found = endpoint_str.rfind(':'); + if (found == std::string::npos) { - asio::error_code ec; - asio::ip::address addr = asio::ip::make_address(address, ec); - if (ec) - { - throw std::runtime_error("Invalid address: " + address); - } - return addr; + throw std::runtime_error("Invalid endpoint: " + endpoint_str); } -} -/// Parse port from string, while ignoring the ip. -/// 10.0.0.1 -> error::invalid_argument -/// 10.0.0.1:9900 -> 9900 -inline auto parse_port(const std::string& address) -> uint16_t -{ - // If there is a port - std::size_t found = address.rfind(':'); - if (found != std::string::npos) - { - auto port = address.substr(found + 1, std::string::npos); - return std::atoi(port.c_str()); - } - else + asio::error_code ec; + asio::ip::address addr = + asio::ip::make_address(endpoint_str.substr(0, found), ec); + if (ec) { - return 0; + throw std::runtime_error("Invalid address: " + endpoint_str); } -} -inline auto -to_udp_endpoint(const std::string& address) -> asio::ip::udp::endpoint -{ - asio::ip::address addr = parse_ip(address); - uint16_t port = parse_port(address); + + uint16_t port = std::atoi(endpoint_str.substr(found + 1).c_str()); + return {addr, port}; } -asio::ip::udp::endpoint peer; + auto rx_udp_tx_tun(asio::ip::udp::socket& rx, - asio::posix::stream_descriptor& tx) -> void + asio::posix::stream_descriptor& tx, + asio::ip::udp::endpoint& peer) -> void { static uint8_t buffer[2000]; rx.async_receive_from(asio::buffer(buffer, sizeof(buffer)), peer, @@ -91,11 +57,12 @@ auto rx_udp_tx_tun(asio::ip::udp::socket& rx, { assert(!err); tx.write_some(asio::buffer(buffer, len)); - rx_udp_tx_tun(rx, tx); + rx_udp_tx_tun(rx, tx, peer); }); } auto rx_tun_tx_udp(asio::posix::stream_descriptor& rx, - asio::ip::udp::socket& tx) -> void + asio::ip::udp::socket& tx, + const asio::ip::udp::endpoint& peer) -> void { static uint8_t buffer[2000]; rx.async_read_some(asio::buffer(buffer, sizeof(buffer)), @@ -105,85 +72,108 @@ auto rx_tun_tx_udp(asio::posix::stream_descriptor& rx, { tx.send_to(asio::buffer(buffer, len), peer); } - rx_tun_tx_udp(rx, tx); + rx_tun_tx_udp(rx, tx, peer); }); } +struct EndpointValidator : public CLI::Validator +{ + EndpointValidator() + { + name_ = "ENDPOINT"; + func_ = [](const std::string& str) -> std::string + { + try + { + to_endpoint(str); + } + catch (const std::exception& e) + { + return e.what(); + } + return std::string(); + }; + } +}; + int main(int argc, char** argv) { enable_core_dumps(); - CLI::App app{"Tunnel back-to-back test app"}; - std::string mode = ""; std::string tunnel_address = ""; std::string local_address = ""; std::string remote_address = ""; - app.add_option("-m", mode, "Tunnel mode tun/tap")->required(); - app.add_option("-a", tunnel_address, "Tunnel address")->required(); - app.add_option("-l", local_address, "UDP local address"); - app.add_option("-r", remote_address, "UDP remote address"); - auto log1 = [](auto, const std::string& message, auto) - { std::cout << "tunnel_iface: " << message << std::endl; }; + CLI::App app{"Tunnel back-to-back test app"}; + + app.add_option("-m,--mode", mode, "Tunnel mode tun/tap") + ->check(CLI::IsMember({"tun", +#if defined(PLATFORM_LINUX) // Tap is only supported on Linux + "tap" +#endif + })) + ->required(); + app.add_option("-a,--tunnel", tunnel_address, + "Tunnel address, e.g. 11.11.11.11") + ->check(CLI::ValidIPV4) + ->required(); + + auto local_option = + app.add_option("-l,--local", local_address, "UDP local endpoint") + ->check(EndpointValidator()); + auto remote_option = + app.add_option("-r,--remote", remote_address, "UDP remote endpoint") + ->check(EndpointValidator()); + + // Make sure that local and remote address are mutually exclusive + local_option->excludes(remote_option); + remote_option->excludes(local_option); + + // Add a validation callback to enforce that either local or remote address + // is specified + app.final_callback( + [&]() + { + if (local_address.empty() && remote_address.empty()) + { + throw CLI::RequiredError("Either --local or --remote"); + } + }); CLI11_PARSE(app, argc, argv); - assert((!local_address.empty() || !remote_address.empty()) && - "Either remote or local address must be specified"); - assert(!tunnel_address.empty() && "Empty tunnel address"); asio::io_context io; asio::ip::udp::socket udp_socket(io, asio::ip::udp::v4()); + asio::ip::udp::endpoint peer; if (!local_address.empty()) { - auto ep = to_udp_endpoint(local_address); - udp_socket.bind(ep); + udp_socket.bind(to_endpoint(local_address)); } else if (!remote_address.empty()) { - auto ep = to_udp_endpoint(remote_address); - peer = ep; + peer = to_endpoint(remote_address); } - if (mode == "tun") - { - tunnel::tun_interface iface1; - iface1.create({}); - iface1.set_log_callback(log1); - iface1.monitor().enable_log(); - iface1.set_ipv4(tunnel_address); - iface1.set_ipv4_netmask("255.255.255.0"); - iface1.set_mtu(1500); - iface1.up(); - auto in_fd = iface1.native_handle(); - assert(in_fd > 0 && "Invalid file descriptor"); - auto rx = asio::posix::stream_descriptor(io); - rx.assign(in_fd); - rx_tun_tx_udp(rx, udp_socket); - rx_udp_tx_tun(udp_socket, rx); - io.run(); - } - else if (mode == "tap") - { -#if defined(PLATFORM_MAC) - std::cerr << "Tap mode is not supported on MacOS" << std::endl; - exit(-1); -#endif - tunnel::tap_interface iface1; - iface1.create({}); - iface1.set_log_callback(log1); - iface1.monitor().enable_log(); - iface1.set_ipv4(tunnel_address); - iface1.set_ipv4_netmask("255.255.255.0"); - iface1.set_mtu(1500); - iface1.up(); - auto in_fd = iface1.native_handle(); - assert(in_fd > 0 && "Invalid file descriptor"); - auto rx = asio::posix::stream_descriptor(io); - rx.assign(in_fd); - rx_tun_tx_udp(rx, udp_socket); - rx_udp_tx_tun(udp_socket, rx); - io.run(); - } + auto log1 = [](auto, const std::string& message, auto) + { std::cout << "tunnel_iface: " << message << std::endl; }; + tunnel::interface::config config; + config.interface_type = mode == "tun" ? tunnel::interface::type::tun + : tunnel::interface::type::tap; + tunnel::interface iface1; + iface1.create(config); + iface1.set_log_callback(log1); + iface1.monitor().enable_log(); + iface1.set_ipv4(tunnel_address); + iface1.set_ipv4_netmask("255.255.255.0"); + iface1.set_mtu(1500); + iface1.up(); + auto in_fd = iface1.native_handle(); + assert(in_fd > 0 && "Invalid file descriptor"); + auto rx = asio::posix::stream_descriptor(io); + rx.assign(in_fd); + rx_tun_tx_udp(rx, udp_socket, peer); + rx_udp_tx_tun(udp_socket, rx, peer); + io.run(); return 0; } diff --git a/examples/interface.cpp b/examples/interface.cpp index 2e9ec6d..c8da904 100644 --- a/examples/interface.cpp +++ b/examples/interface.cpp @@ -3,7 +3,7 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include #include #include @@ -14,24 +14,32 @@ int main() auto log = [](auto, const std::string& message, auto) { std::cout << message << std::endl; }; - tunnel::tun_interface iface; + tunnel::interface iface; iface.set_log_callback(log); iface.monitor().enable_log(); #if defined(PLATFORM_LINUX) - iface.create({"tuniface"}); -#elif defined(PLATFORM_MAC) - iface.create({}); -#endif - + iface.create({tunnel::interface::type::tun, "tuniface"}); if (iface.is_up()) { iface.set_non_persistent(); return 0; } +#elif defined(PLATFORM_MAC) + iface.create({}); + if (iface.is_up()) + { + iface.down(); + } +#endif #if defined(PLATFORM_LINUX) assert(iface.interface_name() == "tuniface"); + + assert(iface.is_persistent() == false); + iface.set_persistent(); + assert(iface.is_persistent() == true); + iface.set_non_persistent(); #elif defined(PLATFORM_MAC) const std::string expected_interface_name = "utun"; // on macOS the interface name is not known in advance and must @@ -40,10 +48,6 @@ int main() std::string::npos); #endif - assert(iface.is_persistent() == false); - iface.set_persistent(); - assert(iface.is_persistent() == true); - iface.set_mtu(1000); assert(iface.mtu() == 1000); diff --git a/examples/read_data.cpp b/examples/read_data.cpp index 705261c..7a48259 100644 --- a/examples/read_data.cpp +++ b/examples/read_data.cpp @@ -3,7 +3,7 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include #include #include @@ -25,14 +25,13 @@ int main() auto log = [](auto, const std::string& message, auto) { std::cout << message << std::endl; }; - tunnel::tun_interface iface; + tunnel::interface iface; iface.set_log_callback(log); iface.monitor().enable_log(); iface.create({}); iface.set_ipv4("10.0.0.1"); iface.set_ipv4_netmask("255.255.255.0"); - iface.set_persistent(); iface.set_mtu(1500); iface.up(); diff --git a/examples/sample_tunnel.cpp b/examples/sample_tunnel.cpp index 41dcc87..c7d7cfc 100644 --- a/examples/sample_tunnel.cpp +++ b/examples/sample_tunnel.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include @@ -169,7 +169,7 @@ int main(int argc, char* argv[]) "udp tunnel." << std::endl; - tunnel::tun_interface iface; + tunnel::interface iface; iface.create({}); iface.up(); diff --git a/lock_version_resolve.json b/lock_version_resolve.json index 1e32108..6b97f9a 100644 --- a/lock_version_resolve.json +++ b/lock_version_resolve.json @@ -60,13 +60,13 @@ "sha1": "f6bc772cf920c024726ebd12a5a38f123d057adb" }, "poke": { - "commit_id": "17efddfa40a5d8a7ad2e7912f385c2ace5bfcb71", - "resolver_info": "13.0.0", + "commit_id": "90f724319a2a48b48ec2227428ebee5187b9b6c8", + "resolver_info": "13.0.3", "sha1": "792e4aecebe15ef24e9aa66a000b2751c485c340" }, "protobuf": { - "commit_id": "8c097d481bb76bafafea87d56c8627c9b82014cd", - "resolver_info": "2.0.9", + "commit_id": "1e7b3114dd9ed4fcfe5f0969033235d7295004c7", + "resolver_info": "2.0.12", "sha1": "1cbce41d76e6829eb713e60eb7c3f46a1a350a32" }, "protobuf-source": { diff --git a/src/tunnel/detail/log_kind.hpp b/src/tunnel/detail/log_kind.hpp index 36a78d6..7a5bd5e 100644 --- a/src/tunnel/detail/log_kind.hpp +++ b/src/tunnel/detail/log_kind.hpp @@ -75,10 +75,10 @@ enum class log_kind disable_default_route, /// Getting the interface ipv4 address - interface_ipv4, + ipv4, /// Getting the interface ipv4 netmask - interface_ipv4_netmask, + ipv4_netmask, /// Setting the interface ipv4 address set_ipv4, diff --git a/src/tunnel/detail/platform_linux/error_tags.hpp b/src/tunnel/detail/platform_linux/error_tags.hpp index 263c4d0..38669ee 100644 --- a/src/tunnel/detail/platform_linux/error_tags.hpp +++ b/src/tunnel/detail/platform_linux/error_tags.hpp @@ -10,7 +10,7 @@ ERROR_TAG(interface_name_too_long, ERROR_TAG(mtu_too_large, "The MTU value specified is too large.") ERROR_TAG(nlmsg_ok, "Got false from NLMSG_OK macro.") ERROR_TAG(nlmsg_error, "Got a NLMSG_ERROR.") - +ERROR_TAG(invalid_interface_type, "Invalid interface type.") #else #error "Missing ERROR_TAG" #endif diff --git a/src/tunnel/detail/layer_final.hpp b/src/tunnel/detail/platform_linux/layer_final.hpp similarity index 93% rename from src/tunnel/detail/layer_final.hpp rename to src/tunnel/detail/platform_linux/layer_final.hpp index a6963f7..7c5298b 100644 --- a/src/tunnel/detail/layer_final.hpp +++ b/src/tunnel/detail/platform_linux/layer_final.hpp @@ -9,6 +9,8 @@ namespace tunnel { namespace detail { +namespace platform_linux +{ template class layer_final { @@ -25,3 +27,4 @@ class layer_final }; } } +} diff --git a/src/tunnel/detail/platform_linux/layer_tun.hpp b/src/tunnel/detail/platform_linux/layer_interface.hpp similarity index 77% rename from src/tunnel/detail/platform_linux/layer_tun.hpp rename to src/tunnel/detail/platform_linux/layer_interface.hpp index 7ac97ed..f0dd405 100644 --- a/src/tunnel/detail/platform_linux/layer_tun.hpp +++ b/src/tunnel/detail/platform_linux/layer_interface.hpp @@ -12,29 +12,19 @@ #include #include - -#include -#include - -// clang-format off -#include -#include #include -// clang-format on - #include #include #include +#include +#include -#include "error.hpp" -#include "scoped_file_descriptor.hpp" - +#include "../../interface.hpp" +#include "../../log_level.hpp" #include "../log.hpp" #include "../log_kind.hpp" - -#include "../../log_level.hpp" - -#include "../../interface_config.hpp" +#include "../scoped_file_descriptor.hpp" +#include "error.hpp" namespace tunnel { @@ -44,10 +34,10 @@ namespace platform_linux { template -struct layer_tun : public Super +struct layer_interface : public Super { - void create(const config& config, std::error_code& error) + void create(const tunnel::interface::config& config, std::error_code& error) { assert(!error); @@ -66,8 +56,7 @@ struct layer_tun : public Super } // Open the TUN driver - const char* tun_device = "/dev/net/tun"; - m_tun_fd = Super::open(tun_device, O_RDWR, error); + m_interface_fd = Super::open("/dev/net/tun", O_RDWR, error); if (error) { @@ -78,8 +67,24 @@ struct layer_tun : public Super struct ifreq ifr { }; - - ifr.ifr_flags = IFF_TUN; + switch (config.interface_type) + { + case tunnel::interface::type::tun: + { + ifr.ifr_flags = IFF_TUN; + break; + } + case tunnel::interface::type::tap: + { + ifr.ifr_flags = IFF_TAP; + break; + } + default: + { + error = make_error_code(linux_error::invalid_interface_type); + return; + } + } // Do not prepend a protocol information header. // @@ -110,7 +115,7 @@ struct layer_tun : public Super config.interface_name.size()); } - Super::ioctl(m_tun_fd, TUNSETIFF, (void*)&ifr, error); + Super::ioctl(m_interface_fd, TUNSETIFF, (void*)&ifr, error); if (error) { return; @@ -118,11 +123,20 @@ struct layer_tun : public Super if (config.vnet_hdr) { - int offload_flags = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_UFO; - Super::ioctl(m_tun_fd, TUNSETOFFLOAD, offload_flags, error); - if (error) + if (config.interface_type == tunnel::interface::type::tun) + { + int offload_flags = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_UFO; + Super::ioctl(m_interface_fd, TUNSETOFFLOAD, offload_flags, + error); + if (error) + { + return; + } + } + else if (config.interface_type == tunnel::interface::type::tap) { - return; + // there are some support for offloading but it is not clear how + // and if they work } } @@ -180,7 +194,7 @@ struct layer_tun : public Super return; } - Super::ioctl(m_tun_fd, TUNSETOWNER, (void*)(intptr_t)pwd->pw_uid, + Super::ioctl(m_interface_fd, TUNSETOWNER, (void*)(intptr_t)pwd->pw_uid, error); } @@ -219,7 +233,7 @@ struct layer_tun : public Super { assert(!error); assert(!group.empty()); - assert(m_tun_fd); + assert(m_interface_fd); Super::do_log(log_level::debug, log_kind::set_group, log::str{"group", group.c_str()}); @@ -232,19 +246,19 @@ struct layer_tun : public Super return; } - Super::ioctl(m_tun_fd, TUNSETGROUP, (void*)(intptr_t)grp->gr_gid, + Super::ioctl(m_interface_fd, TUNSETGROUP, (void*)(intptr_t)grp->gr_gid, error); } auto is_persistent(std::error_code& error) const -> bool { - assert(m_tun_fd); + assert(m_interface_fd); assert(!error); struct ifreq ifr { }; - Super::ioctl(m_tun_fd, TUNGETIFF, (void*)&ifr, error); + Super::ioctl(m_interface_fd, TUNGETIFF, (void*)&ifr, error); bool persistent = ifr.ifr_flags & IFF_PERSIST; @@ -255,35 +269,35 @@ struct layer_tun : public Super void set_persistent(std::error_code& error) const { - assert(m_tun_fd); + assert(m_interface_fd); assert(!error); Super::do_log(log_level::debug, log_kind::set_persistent, log::str{"", ""}); - Super::ioctl(m_tun_fd, TUNSETPERSIST, (void*)1, error); + Super::ioctl(m_interface_fd, TUNSETPERSIST, (void*)1, error); } void set_non_persistent(std::error_code& error) const { - assert(m_tun_fd); + assert(m_interface_fd); assert(!error); Super::do_log(log_level::debug, log_kind::set_non_persistent, log::str{"", ""}); - Super::ioctl(m_tun_fd, TUNSETPERSIST, (void*)0, error); + Super::ioctl(m_interface_fd, TUNSETPERSIST, (void*)0, error); } auto interface_name(std::error_code& error) const -> std::string { - assert(m_tun_fd); + assert(m_interface_fd); assert(!error); struct ifreq ifr { }; - Super::ioctl(m_tun_fd, TUNGETIFF, (void*)&ifr, error); + Super::ioctl(m_interface_fd, TUNGETIFF, (void*)&ifr, error); Super::do_log(log_level::debug, log_kind::interface_name, log::str{"name", ifr.ifr_name}); @@ -293,12 +307,12 @@ struct layer_tun : public Super auto native_handle() const -> int { - assert(m_tun_fd); + assert(m_interface_fd); Super::do_log(log_level::debug, log_kind::native_handle, - log::integer{"handle", m_tun_fd.native_handle()}); + log::integer{"handle", m_interface_fd.native_handle()}); - return m_tun_fd.native_handle(); + return m_interface_fd.native_handle(); } private: @@ -345,7 +359,7 @@ struct layer_tun : public Super } private: - scoped_file_descriptor m_tun_fd; + scoped_file_descriptor m_interface_fd; }; } } diff --git a/src/tunnel/detail/platform_linux/layer_linux.hpp b/src/tunnel/detail/platform_linux/layer_linux.hpp index 73fb912..af2973a 100644 --- a/src/tunnel/detail/platform_linux/layer_linux.hpp +++ b/src/tunnel/detail/platform_linux/layer_linux.hpp @@ -18,7 +18,7 @@ #include "../log.hpp" #include "../log_kind.hpp" -#include "scoped_file_descriptor.hpp" +#include "../scoped_file_descriptor.hpp" namespace tunnel { @@ -97,6 +97,7 @@ struct layer_linux : public Super Super::do_log(log_level::error, log_kind::ioctl, log::uinteger{"request", request}, log::str{"error", error.message().c_str()}); + return; } Super::do_log(log_level::debug, log_kind::ioctl, @@ -119,6 +120,7 @@ struct layer_linux : public Super Super::do_log(log_level::error, log_kind::ioctl, log::uinteger{"request", request}, log::str{"error", error.message().c_str()}); + return; } Super::do_log(log_level::debug, log_kind::ioctl, diff --git a/src/tunnel/detail/layer_monitor.hpp b/src/tunnel/detail/platform_linux/layer_monitor.hpp similarity index 90% rename from src/tunnel/detail/layer_monitor.hpp rename to src/tunnel/detail/platform_linux/layer_monitor.hpp index 9a817a6..b417e2f 100644 --- a/src/tunnel/detail/layer_monitor.hpp +++ b/src/tunnel/detail/platform_linux/layer_monitor.hpp @@ -10,18 +10,18 @@ #include #include -#include "monitor.hpp" - -#include "log.hpp" -#include "log_kind.hpp" -#include "to_json_property.hpp" - -#include "../log_level.hpp" +#include "../../log_level.hpp" +#include "../log.hpp" +#include "../log_kind.hpp" +#include "../monitor.hpp" +#include "../to_json_property.hpp" namespace tunnel { namespace detail { +namespace platform_linux +{ template class layer_monitor : public Super @@ -75,3 +75,4 @@ class layer_monitor : public Super }; } } +} diff --git a/src/tunnel/detail/platform_linux/layer_netdevice.hpp b/src/tunnel/detail/platform_linux/layer_netdevice.hpp index 83f0e88..8672193 100644 --- a/src/tunnel/detail/platform_linux/layer_netdevice.hpp +++ b/src/tunnel/detail/platform_linux/layer_netdevice.hpp @@ -17,10 +17,10 @@ #include "../log.hpp" #include "../log_kind.hpp" +#include "../scoped_file_descriptor.hpp" #include "error.hpp" -#include "scoped_file_descriptor.hpp" -#include "../../interface_config.hpp" +#include "../../interface.hpp" #include "../../log_level.hpp" namespace tunnel @@ -35,7 +35,7 @@ template class layer_netdevice : public Super { public: - void create(const config& config, std::error_code& error) + void create(const tunnel::interface::config& config, std::error_code& error) { assert(!error); @@ -327,7 +327,7 @@ class layer_netdevice : public Super struct sockaddr_in* addr_in = (struct sockaddr_in*)&ifr.ifr_addr; - Super::do_log(log_level::debug, log_kind::interface_ipv4, + Super::do_log(log_level::debug, log_kind::ipv4, log::str{"ip", ::inet_ntoa(addr_in->sin_addr)}); return ::inet_ntoa(addr_in->sin_addr); @@ -353,7 +353,7 @@ class layer_netdevice : public Super struct sockaddr_in* addr_in = (struct sockaddr_in*)&ifr.ifr_addr; - Super::do_log(log_level::debug, log_kind::interface_ipv4_netmask, + Super::do_log(log_level::debug, log_kind::ipv4_netmask, log::str{"netmask", ::inet_ntoa(addr_in->sin_addr)}); return ::inet_ntoa(addr_in->sin_addr); diff --git a/src/tunnel/detail/platform_linux/layer_netlink_v4.hpp b/src/tunnel/detail/platform_linux/layer_netlink_v4.hpp index ffd4916..ceeb762 100644 --- a/src/tunnel/detail/platform_linux/layer_netlink_v4.hpp +++ b/src/tunnel/detail/platform_linux/layer_netlink_v4.hpp @@ -5,19 +5,16 @@ #pragma once -#include #include +#include #include +#include +#include -#include -#include - +#include #include - #include #include - -#include #include #include #include @@ -25,18 +22,15 @@ #include #include #include -#include #include -#include -#include "../../interface_config.hpp" +#include "../../interface.hpp" +#include "../../log_level.hpp" #include "../log.hpp" #include "../log_kind.hpp" +#include "../scoped_file_descriptor.hpp" #include "error.hpp" #include "if_nametoindex.hpp" -#include "scoped_file_descriptor.hpp" - -#include "../../log_level.hpp" namespace tunnel { @@ -75,7 +69,7 @@ template class layer_netlink_v4 : public Super { public: - void create(const config& config, std::error_code& error) + void create(const tunnel::interface::config& config, std::error_code& error) { assert(!error); @@ -128,7 +122,7 @@ class layer_netlink_v4 : public Super return false; } - std::string tun_interface = Super::interface_name(error); + std::string interface_name = Super::interface_name(error); if (error) { @@ -137,9 +131,9 @@ class layer_netlink_v4 : public Super Super::do_log(log_level::debug, log_kind::is_default_route, log::boolean{"is_default_route", - default_interface == tun_interface}); + default_interface == interface_name}); - return default_interface == tun_interface; + return default_interface == interface_name; } private: diff --git a/src/tunnel/detail/platform_linux/layer_tap.hpp b/src/tunnel/detail/platform_linux/layer_tap.hpp deleted file mode 100644 index 59585e4..0000000 --- a/src/tunnel/detail/platform_linux/layer_tap.hpp +++ /dev/null @@ -1,345 +0,0 @@ - -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include -#include - -// clang-format off -#include -#include -#include -// clang-format on - -#include -#include -#include - -#include "error.hpp" -#include "scoped_file_descriptor.hpp" - -#include "../log.hpp" -#include "../log_kind.hpp" - -#include "../../interface_config.hpp" -#include "../../log_level.hpp" - -namespace tunnel -{ -namespace detail -{ -namespace platform_linux -{ - -template -struct layer_tap : public Super -{ - - void create(const config& config, std::error_code& error) - { - assert(!error); - - // Check that the interface name is not too long - // Seems in this patch the name has to be zero-terminated so the actual - // size we can use is IFNAMSIZ - 1: - // https://www.spinics.net/lists/netdev/msg445126.html - if (config.interface_name.size() > IFNAMSIZ - 1) - { - error = make_error_code(linux_error::interface_name_too_long); - - Super::do_log(log_level::error, log_kind::interface_created, - log::str{"error", error.message().c_str()}); - assert(error); - return; - } - - // Open the TUN driver - const char* tun_device = "/dev/net/tun"; - m_tun_fd = Super::open(tun_device, O_RDWR, error); - - if (error) - { - return; - } - - // Create the TUN interface - struct ifreq ifr - { - }; - - ifr.ifr_flags = IFF_TAP; - - // Do not prepend a protocol information header. - // - // *Without* the IFF_NO_PI flag, the driver will send the following; - // two bytes of flags, two bytes of protocol type, and then the actual - // network packet. - // Since the first two values are largely redundant, most applications - // will probably want to set this flag, hence we do so here. - if (config.iff_no_pi) - { - ifr.ifr_flags |= IFF_NO_PI; - } - - // If the vnet_hdr flag is set, we want to enable the virtio-net-header - // feature. This feature is used to pass additional information about - // GSO packets to and from the kernel. - if (config.vnet_hdr) - { - ifr.ifr_flags |= IFF_VNET_HDR; - } - - // If a device name was specified, put it in the structure; - // otherwise, the kernel will try to allocate the "next" device of - // the specified type - if (!config.interface_name.empty()) - { - config.interface_name.copy(ifr.ifr_name, - config.interface_name.size()); - } - - Super::ioctl(m_tun_fd, TUNSETIFF, (void*)&ifr, error); - if (error) - { - return; - } - - // there are some support for offloading but it is not clear how and if - // they work - - Super::do_log(log_level::debug, log_kind::interface_created, - log::str{"name", config.interface_name.c_str()}, - log::boolean{"vnet_hdr", config.vnet_hdr}); - } - - auto owner(std::error_code& error) const -> std::string - { - assert(!error); - - std::string o = read_property("owner", error); - - Super::do_log(log_level::debug, log_kind::owner, - log::str{"owner", o.c_str()}); - - if (error) - { - return {}; - } - - int uid = stoi(o, nullptr); - - if (uid == -1) - { - // https://unix.stackexchange.com/a/278488 - return {}; - } - - struct passwd* pwd = getpwuid(uid); - - if (pwd == nullptr) - { - error.assign(errno, std::generic_category()); - return {}; - } - - return pwd->pw_name; - } - - void set_owner(const std::string& owner, std::error_code& error) const - { - assert(!error); - assert(!owner.empty()); - - Super::do_log(log_level::debug, log_kind::set_owner, - log::str{"owner", owner.c_str()}); - - struct passwd* pwd = getpwnam(owner.c_str()); - - if (pwd == nullptr) - { - error.assign(errno, std::generic_category()); - return; - } - - Super::ioctl(m_tun_fd, TUNSETOWNER, (void*)(intptr_t)pwd->pw_uid, - error); - } - - auto group(std::error_code& error) const -> std::string - { - std::string o = read_property("group", error); - - Super::do_log(log_level::debug, log_kind::group, - log::str{"group", o.c_str()}); - - if (error) - { - return {}; - } - - int uid = stoi(o, nullptr); - - if (uid == -1) - { - // https://unix.stackexchange.com/a/278488 - return {}; - } - - struct group* grp = getgrgid(uid); - - if (grp == nullptr) - { - error.assign(errno, std::generic_category()); - return {}; - } - - return grp->gr_name; - } - - void set_group(const std::string& group, std::error_code& error) const - { - assert(!error); - assert(!group.empty()); - assert(m_tun_fd); - - Super::do_log(log_level::debug, log_kind::set_group, - log::str{"group", group.c_str()}); - - struct group* grp = getgrnam(group.c_str()); - - if (grp == nullptr) - { - error.assign(errno, std::generic_category()); - return; - } - - Super::ioctl(m_tun_fd, TUNSETGROUP, (void*)(intptr_t)grp->gr_gid, - error); - } - - auto is_persistent(std::error_code& error) const -> bool - { - assert(m_tun_fd); - assert(!error); - - struct ifreq ifr - { - }; - Super::ioctl(m_tun_fd, TUNGETIFF, (void*)&ifr, error); - - bool persistent = ifr.ifr_flags & IFF_PERSIST; - - Super::do_log(log_level::debug, log_kind::interface_is_persistent, - log::boolean{"persistent", persistent}); - return persistent; - } - - void set_persistent(std::error_code& error) const - { - assert(m_tun_fd); - assert(!error); - - Super::do_log(log_level::debug, log_kind::set_persistent, - log::str{"", ""}); - - Super::ioctl(m_tun_fd, TUNSETPERSIST, (void*)1, error); - } - - void set_non_persistent(std::error_code& error) const - { - assert(m_tun_fd); - assert(!error); - - Super::do_log(log_level::debug, log_kind::set_non_persistent, - log::str{"", ""}); - - Super::ioctl(m_tun_fd, TUNSETPERSIST, (void*)0, error); - } - - auto interface_name(std::error_code& error) const -> std::string - { - assert(m_tun_fd); - assert(!error); - - struct ifreq ifr - { - }; - Super::ioctl(m_tun_fd, TUNGETIFF, (void*)&ifr, error); - - Super::do_log(log_level::debug, log_kind::interface_name, - log::str{"name", ifr.ifr_name}); - - return ifr.ifr_name; - } - - auto native_handle() const -> int - { - assert(m_tun_fd); - - Super::do_log(log_level::debug, log_kind::native_handle, - log::integer{"handle", m_tun_fd.native_handle()}); - - return m_tun_fd.native_handle(); - } - -private: - auto read_property(const std::string& property, - std::error_code& error) const -> std::string - { - std::string name = interface_name(error); - - if (error) - { - return {}; - } - - // https://github.com/sivasankariit/iproute2/blob/master/ip/iptuntap.c#L217 - std::stringstream ss; - ss << "/sys/class/net/" << name << "/" << property; - - scoped_file_descriptor fd = Super::open(ss.str(), O_RDONLY, error); - - if (error) - { - return {}; - } - - uint32_t size = Super::size(fd, error); - - if (error) - { - return {}; - } - - std::vector data(size, 0); - - Super::read(fd, data.data(), data.size(), error); - - if (error) - { - return {}; - } - - std::string value(data.begin(), data.end()); - - return value; - } - -private: - scoped_file_descriptor m_tun_fd; -}; -} -} -} diff --git a/src/tunnel/detail/platform_linux/stack_tun_interface.hpp b/src/tunnel/detail/platform_linux/stack_interface.hpp similarity index 70% rename from src/tunnel/detail/platform_linux/stack_tun_interface.hpp rename to src/tunnel/detail/platform_linux/stack_interface.hpp index 556d003..9cb6a9e 100644 --- a/src/tunnel/detail/platform_linux/stack_tun_interface.hpp +++ b/src/tunnel/detail/platform_linux/stack_interface.hpp @@ -23,13 +23,13 @@ #include "error.hpp" #include "layer_linux.hpp" +#include "../scoped_file_descriptor.hpp" +#include "layer_interface.hpp" #include "layer_netdevice.hpp" #include "layer_netlink_v4.hpp" -#include "layer_tun.hpp" -#include "scoped_file_descriptor.hpp" -#include "../layer_final.hpp" -#include "../layer_monitor.hpp" +#include "layer_final.hpp" +#include "layer_monitor.hpp" namespace tunnel { @@ -41,22 +41,17 @@ namespace platform_linux /// here: https://www.kernel.org/doc/Documentation/networking/tuntap.txt // clang-format off -struct stack_tun_interface : public +struct stack_interface : public layer_netlink_v4< layer_netdevice< - layer_tun< + layer_interface< layer_linux< layer_monitor< - layer_final>>>>> + layer_final>>>>> { - static auto is_platform_supported() -> bool - { - return true; - } - static auto type() -> std::string { - return "tunnel::detail::platform_linux::stack_tun_interface"; + return "tunnel::detail::platform_linux::stack_interface"; } }; // clang-format on diff --git a/src/tunnel/detail/platform_linux/stack_tap_interface.hpp b/src/tunnel/detail/platform_linux/stack_tap_interface.hpp deleted file mode 100644 index b3f04c6..0000000 --- a/src/tunnel/detail/platform_linux/stack_tap_interface.hpp +++ /dev/null @@ -1,66 +0,0 @@ - -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#include "error.hpp" -#include "layer_linux.hpp" - -#include "layer_netdevice.hpp" -#include "layer_netlink_v4.hpp" -#include "layer_tap.hpp" -#include "scoped_file_descriptor.hpp" - -#include "../layer_final.hpp" -#include "../layer_monitor.hpp" - -namespace tunnel -{ -namespace detail -{ -namespace platform_linux -{ -/// In Linux you can find the documentation for TAP/TAP devices -/// here: https://www.kernel.org/doc/Documentation/networking/tuntap.txt - -// clang-format off -struct stack_tap_interface : public - layer_netlink_v4< - layer_netdevice< - layer_tap< - layer_linux< - layer_monitor< - layer_final>>>>> -{ - static auto is_platform_supported() -> bool - { - return true; - } - - static auto type() -> std::string - { - return "tunnel::detail::platform_linux::stack_tap_interface"; - } -}; -// clang-format on -} -} -} diff --git a/src/tunnel/detail/platform_macos/tun_interface.hpp b/src/tunnel/detail/platform_macos/interface.hpp similarity index 55% rename from src/tunnel/detail/platform_macos/tun_interface.hpp rename to src/tunnel/detail/platform_macos/interface.hpp index ef169c2..4be8fd4 100644 --- a/src/tunnel/detail/platform_macos/tun_interface.hpp +++ b/src/tunnel/detail/platform_macos/interface.hpp @@ -1,5 +1,9 @@ -#include "../../interface_config.hpp" +// Copyright (c) 2016 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + #include #include #include @@ -10,28 +14,23 @@ #include #include #include +#include +#include #include #include +#include #include +#include #include #include #include -// #include "../../log_level.hpp" + +#include "../../interface.hpp" +#include "../../log_level.hpp" #include "../log_kind.hpp" #include "../monitor.hpp" -#include -#include -#include -#include - -#include // strlcpy - -#include // UTUN_CONTROL_NAME -#include // ioctl -#include // struct socketaddr_ctl - +#include "../scoped_file_descriptor.hpp" #include "../to_json_property.hpp" -#include namespace tunnel { @@ -40,65 +39,69 @@ namespace detail namespace platform_macos { -class tun_interface +class interface { public: - tun_interface() : - m_monitor("tunnel::detail::platform_macos::utun_interface", {}) + interface() : m_monitor("platform_macos::interface", {}) { } - ~tun_interface() + ~interface() { cleanup(); } // create the utun device - void create(const config& config, std::error_code& error) + void create(const tunnel::interface::config& config, std::error_code& error) { - assert(m_interface_fd == -1 && - "Cannot create an already created device."); + assert(!m_interface_fd && "Cannot create an already created device."); + + if (config.interface_type != tunnel::interface::type::tun) + { + do_log(log_level::error, log_kind::open, + poke::log::str{"error", "Only TUN is supported on MacOS"}); + error = std::make_error_code(std::errc::not_supported); + return; + } - m_control_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (m_control_fd < 0) + scoped_file_descriptor control_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (!control_fd) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"control_fd", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } - m_route_fd = socket(AF_ROUTE, SOCK_RAW, AF_INET); - if (m_route_fd < 0) + scoped_file_descriptor route_fd = socket(AF_ROUTE, SOCK_RAW, AF_INET); + if (!route_fd) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"route_fd", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } struct ctl_info ctlInfo; strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)); - m_interface_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); - if (m_interface_fd < 0) + scoped_file_descriptor interface_fd = + socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (!interface_fd) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"interface_fd", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } + // Get the control ID struct sockaddr_ctl sc; memset(&sc, 0, sizeof(sc)); - if (ioctl(m_interface_fd, CTLIOCGINFO, &ctlInfo) == -1) + if (ioctl(interface_fd.native_handle(), CTLIOCGINFO, &ctlInfo) == -1) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"get_control_id", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } @@ -108,9 +111,8 @@ class tun_interface int sock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); if (sock < 0) { - m_monitor.m_monitor.log( - poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"find_unit", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return -1; } @@ -132,18 +134,16 @@ class tun_interface } close(sock); } - m_monitor.m_monitor.log( - poke::log_level::error, log_kind::open, - poke::log::str{"error", "No free unit found"}); + do_log(log_level::error, log_kind::open, + poke::log::str{"error", "No free unit found"}); error = std::make_error_code(std::errc::io_error); return -1; }; // Scan for a free unit number - m_unit = find_free_unit(); - if (m_unit == -1) + int unit = find_free_unit(); + if (unit == -1) { - cleanup(); return; } @@ -151,48 +151,40 @@ class tun_interface sc.sc_len = sizeof(sc); sc.sc_family = AF_SYSTEM; sc.ss_sysaddr = AF_SYS_CONTROL; - sc.sc_unit = m_unit; + sc.sc_unit = unit; - if (connect(m_interface_fd, (struct sockaddr*)&sc, sizeof(sc)) < 0) + if (connect(interface_fd.native_handle(), (struct sockaddr*)&sc, + sizeof(sc)) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"connect", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } // Set non-blocking mode - if (fcntl(m_interface_fd, F_SETFL, O_NONBLOCK) < 0) + if (fcntl(interface_fd.native_handle(), F_SETFL, O_NONBLOCK) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::open, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::open, + poke::log::str{"set_non_blocking", strerror(errno)}); error = std::make_error_code(std::errc::io_error); - cleanup(); return; } // Construct the interface name - m_name = "utun" + std::to_string(m_unit - 1); + // on macOS the interface name must contain "utun" as a substring + m_name = "utun" + std::to_string(unit - 1); + + // Set the interface file descriptors + m_interface_fd = std::move(interface_fd); + m_control_fd = std::move(control_fd); + m_route_fd = std::move(route_fd); + m_unit = unit; } // Close the utun device void cleanup() { - if (m_control_fd != -1) - { - ::close(m_control_fd); - } - if (m_interface_fd != -1) - { - ::close(m_interface_fd); - m_interface_fd = -1; - } - if (m_route_fd != -1) - { - ::close(m_route_fd); - m_route_fd = -1; - } m_unit = -1; } @@ -207,29 +199,22 @@ class tun_interface // Check if the device is open bool - isOpen() const + is_open() const { - return m_interface_fd != -1; + return static_cast(m_interface_fd); } // Get the file descriptor int native_handle() const { - return m_interface_fd; - } - - // Get the device name - std::string getName() const - { - assert(!m_name.empty() && "Device name is empty."); - return m_name; + return m_interface_fd.native_handle(); } // Set IP address and netmask void set_ipv4(const std::string& ipAddress, std::error_code& error) { - assert(isOpen() && "Device is not open."); - assert(m_control_fd != -1 && "Control socket is not open."); + assert(is_open() && "Device is not open."); + assert(m_control_fd && "Control socket is not open."); assert(!error); auto ifr = make_ifreq(); @@ -239,16 +224,16 @@ class tun_interface addr->sin_family = AF_INET; if (inet_pton(AF_INET, ipAddress.c_str(), &addr->sin_addr) <= 0) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::set_ipv4, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::set_ipv4, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } - if (ioctl(m_control_fd, SIOCSIFADDR, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCSIFADDR, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::set_ipv4, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::set_ipv4, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -256,8 +241,8 @@ class tun_interface void set_ipv4_netmask(const std::string& mask, std::error_code& error) { - assert(isOpen() && "Device is not open."); - assert(m_control_fd != -1 && "Control socket is not open."); + assert(is_open() && "Device is not open."); + assert(m_control_fd && "Control socket is not open."); assert(!error); auto ifr = make_ifreq(); @@ -266,19 +251,17 @@ class tun_interface addr->sin_family = AF_INET; if (inet_pton(AF_INET, mask.c_str(), &addr->sin_addr) <= 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::set_ipv4_netmask, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::set_ipv4_netmask, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } ifr.ifr_addr.sa_family = AF_INET; - if (ioctl(m_control_fd, SIOCSIFNETMASK, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCSIFNETMASK, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::set_ipv4_netmask, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::set_ipv4_netmask, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -289,24 +272,15 @@ class tun_interface assert(!error); struct ifreq ifr = make_ifreq(); - - if (error) - { - return ""; - } - - ioctl(m_control_fd, SIOCGIFADDR, &ifr, error); - + ioctl(m_control_fd.native_handle(), SIOCGIFADDR, &ifr, error); if (error) { return ""; } struct sockaddr_in* addr_in = (struct sockaddr_in*)&ifr.ifr_addr; - - m_monitor.m_monitor.log( - poke::log_level::debug, log_kind::interface_ipv4, - poke::log::str{"ip", ::inet_ntoa(addr_in->sin_addr)}); + do_log(log_level::debug, log_kind::ipv4, + poke::log::str{"ip", ::inet_ntoa(addr_in->sin_addr)}); return ::inet_ntoa(addr_in->sin_addr); } @@ -316,23 +290,15 @@ class tun_interface assert(!error); struct ifreq ifr = make_ifreq(); - - if (error) - { - return ""; - } - - ioctl(m_control_fd, SIOCGIFNETMASK, &ifr, error); - + ioctl(m_control_fd.native_handle(), SIOCGIFNETMASK, &ifr, error); if (error) { return ""; } struct sockaddr_in* addr_in = (struct sockaddr_in*)&ifr.ifr_addr; - m_monitor.m_monitor.log( - poke::log_level::debug, log_kind::interface_ipv4_netmask, - poke::log::str{"netmask", ::inet_ntoa(addr_in->sin_addr)}); + do_log(log_level::debug, log_kind::ipv4_netmask, + poke::log::str{"netmask", ::inet_ntoa(addr_in->sin_addr)}); return ::inet_ntoa(addr_in->sin_addr); } @@ -340,16 +306,16 @@ class tun_interface // Set MTU void set_mtu(uint32_t mtu, std::error_code& error) { - assert(isOpen() && "Device is not open."); - assert(m_control_fd != -1 && "Control socket is not open."); + assert(is_open() && "Device is not open."); + assert(m_control_fd && "Control socket is not open."); auto ifr = make_ifreq(); // Set MTU ifr.ifr_mtu = mtu; - if (ioctl(m_control_fd, SIOCSIFMTU, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCSIFMTU, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, log_kind::set_mtu, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::set_mtu, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -359,27 +325,25 @@ class tun_interface // Bring up the interface void up(std::error_code& error) { - assert(isOpen() && "Device is not open."); - assert(m_control_fd != -1 && "Control socket is not open."); + assert(is_open() && "Device is not open."); + assert(m_control_fd && "Control socket is not open."); auto ifr = make_ifreq(); // Get current flags - if (ioctl(m_control_fd, SIOCGIFFLAGS, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCGIFFLAGS, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::interface_up, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::interface_up, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } // Set the interface up ifr.ifr_flags |= IFF_UP; - if (ioctl(m_control_fd, SIOCSIFFLAGS, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCSIFFLAGS, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::interface_up, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::interface_up, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -389,13 +353,7 @@ class tun_interface assert(!error); struct ifreq ifr = make_ifreq(); - - if (error) - { - return false; - } - - ioctl(m_control_fd, SIOCGIFFLAGS, &ifr, error); + ioctl(m_control_fd.native_handle(), SIOCGIFFLAGS, &ifr, error); if (error) { @@ -404,8 +362,8 @@ class tun_interface bool is_if_up = (ifr.ifr_flags & IFF_UP) != 0; - m_monitor.m_monitor.log(poke::log_level::debug, log_kind::is_up, - log::boolean{"is_up", is_if_up}); + do_log(log_level::debug, log_kind::is_up, + log::boolean{"is_up", is_if_up}); return is_if_up; } @@ -413,27 +371,25 @@ class tun_interface // Bring down the interface void down(std::error_code& error) const { - assert(isOpen() && "Device is not open."); - assert(m_control_fd != -1 && "Control socket is not open."); + assert(is_open() && "Device is not open."); + assert(m_control_fd && "Control socket is not open."); auto ifr = make_ifreq(); // Get current flags - if (ioctl(m_control_fd, SIOCGIFFLAGS, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCGIFFLAGS, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::interface_down, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::interface_down, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } // Set the interface down ifr.ifr_flags &= ~IFF_UP; - if (ioctl(m_control_fd, SIOCSIFFLAGS, &ifr) < 0) + if (ioctl(m_control_fd.native_handle(), SIOCSIFFLAGS, &ifr) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::interface_down, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::interface_down, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -441,7 +397,7 @@ class tun_interface auto is_down(std::error_code& error) const -> bool { assert(!error); - m_monitor.m_monitor.log(poke::log_level::debug, log_kind::is_down); + do_log(log_level::debug, log_kind::is_down); return !is_up(error); } @@ -449,7 +405,7 @@ class tun_interface void enable_default_route(std::error_code& error) { assert(!error); - assert(m_route_fd != -1 && "Route socket is not open."); + assert(m_route_fd && "Route socket is not open."); assert(!ipv4(error).empty() && "IP address is empty."); assert(!m_name.empty() && "Interface name is empty."); struct @@ -480,9 +436,8 @@ class tun_interface rtmsg.gw.sin_family = AF_INET; if (inet_pton(AF_INET, ipv4(error).c_str(), &rtmsg.gw.sin_addr) <= 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::enable_default_route, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::enable_default_route, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -497,11 +452,10 @@ class tun_interface rtmsg.hdr.rtm_index = if_nametoindex(m_name.c_str()); // Send the message to the routing socket - if (write(m_route_fd, &rtmsg, sizeof(rtmsg)) < 0) + if (write(m_route_fd.native_handle(), &rtmsg, sizeof(rtmsg)) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::enable_default_route, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::enable_default_route, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -512,7 +466,7 @@ class tun_interface void disable_default_route(std::error_code& error) { assert(!error); - assert(m_route_fd != -1 && "Route socket is not open."); + assert(m_route_fd && "Route socket is not open."); assert(!ipv4(error).empty() && "IP address is empty."); assert(!m_name.empty() && "Interface name is empty."); struct @@ -545,9 +499,8 @@ class tun_interface rtmsg.gw.sin_addr.s_addr = htonl(INADDR_ANY); if (inet_pton(AF_INET, ipv4(error).c_str(), &rtmsg.gw.sin_addr) <= 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::enable_default_route, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::enable_default_route, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } @@ -562,44 +515,33 @@ class tun_interface rtmsg.hdr.rtm_index = if_nametoindex(m_name.c_str()); // Send the message to the routing socket - if (write(m_route_fd, &rtmsg, sizeof(rtmsg)) < 0) + if (write(m_route_fd.native_handle(), &rtmsg, sizeof(rtmsg)) < 0) { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::enable_default_route, - poke::log::str{"error", strerror(errno)}); + do_log(log_level::error, log_kind::enable_default_route, + poke::log::str{"error", strerror(errno)}); error = std::make_error_code(std::errc::io_error); return; } m_is_default_route = false; } - static auto is_platform_supported() -> bool - { - return true; - } - - static auto type() -> std::string - { - return "tunnel::detail::platform_macos::utun_interface"; - } - std::string interface_name(std::error_code& error) const { assert(!m_name.empty() && "Interface name is empty."); return m_name; } - auto mtu(std::error_code& error) -> uint32_t + auto mtu(std::error_code& error) const -> uint32_t { + assert(!error); auto ifr = make_ifreq(); + ioctl(m_control_fd.native_handle(), SIOCGIFMTU, &ifr, error); if (error) { return 0; } - - ioctl(m_control_fd, SIOCGIFMTU, &ifr, error); - m_monitor.m_monitor.log(poke::log_level::debug, log_kind::interface_mtu, - poke::log::integer{"mtu", ifr.ifr_mtu}); + do_log(log_level::debug, log_kind::interface_mtu, + poke::log::integer{"mtu", ifr.ifr_mtu}); return ifr.ifr_mtu; } @@ -609,92 +551,107 @@ class tun_interface return m_is_default_route; } - auto monitor() const -> const tunnel::monitor& - { - return m_monitor; - } - - auto monitor() -> tunnel::monitor& - { - return m_monitor; - } - - void set_log_callback(const log_callback& callback) - { - m_monitor.set_log_callback(callback); - } - // Unsupported methods for MacOS - void rename(const std::string& newName, std::error_code& error) const + void rename(const std::string&, std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } std::string owner(std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } std::string group(std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } - void set_owner(const std::string& owner, std::error_code& error) const + void set_owner(const std::string&, std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } - void set_group(const std::string& group, std::error_code& error) const + void set_group(const std::string&, std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } bool is_persistent(std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return false; } void set_persistent(std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } void set_non_persistent(std::error_code& error) const { - m_monitor.m_monitor.log(poke::log_level::error, - log_kind::unsupported_platform); + assert(!error); + do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } + auto monitor() -> tunnel::monitor& + { + return m_monitor; + } + + auto monitor() const -> const tunnel::monitor& + { + return m_monitor; + } + + void set_log_callback(const tunnel::log_callback& callback) + { + m_monitor.set_log_callback(callback); + } + + void enable_log(log_level level = log_level::state, + std::string path_filter = "", std::string type_filter = "", + std::any user_data = {}) + { + m_monitor.enable_log(level, path_filter, type_filter, user_data); + } + +protected: + template + void do_log(log_level level, const Kind& kind, Args&&... args) const + { + m_monitor.m_monitor.log(static_cast(level), kind, + std::forward(args)...); + } + private: - int m_interface_fd = -1; - int m_control_fd = -1; - int m_route_fd = -1; + tunnel::detail::monitor m_monitor; + scoped_file_descriptor m_interface_fd; + scoped_file_descriptor m_control_fd; + scoped_file_descriptor m_route_fd; int m_unit = -1; // unit number of the utun device std::string m_name; std::string m_ipAddress; std::string m_netmask; uint32_t m_mtu = -1; bool m_is_default_route = false; - tunnel::detail::monitor m_monitor; }; } diff --git a/src/tunnel/detail/platform_unsupported/layer_tap.hpp b/src/tunnel/detail/platform_unsupported/layer_tap.hpp deleted file mode 100644 index 8680d0d..0000000 --- a/src/tunnel/detail/platform_unsupported/layer_tap.hpp +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include -#include - -#include "../../interface_config.hpp" -#include "../../log_level.hpp" -#include "../log_kind.hpp" - -namespace tunnel -{ -namespace detail -{ -namespace platform_unsupported -{ -template -class layer_tap : public Super -{ -public: - void create(const config& config, std::error_code& error) - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void rename(const std::string& interface_name, std::error_code& error) const - { - (void)interface_name; - - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void set_owner(const std::string& owner, std::error_code& error) const - { - (void)owner; - - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void set_group(const std::string& group, std::error_code& error) const - { - (void)group; - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - std::string owner(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return ""; - } - - std::string group(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return ""; - } - - std::string interface_name(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return ""; - } - - bool is_up(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return false; - } - - bool is_down(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return false; - } - - void up(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void down(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - bool is_persistent(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return false; - } - - void set_persistent(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - int mtu(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return 0; - } - - void set_non_persistent(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void set_mtu(int mtu, std::error_code& error) const - { - (void)mtu; - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void set_ipv4(const std::string& address, std::error_code& error) const - { - (void)address; - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void enable_default_route(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - void disable_default_route(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - bool is_default_route(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return false; - } - - std::string ipv4(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return ""; - } - - std::string ipv4_netmask(std::error_code& error) const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - return ""; - } - - void set_ipv4_netmask(const std::string& netmask, - std::error_code& error) const - { - (void)netmask; - - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); - } - - int native_handle() const - { - Super::do_log(log_level::error, log_kind::unsupported_platform); - throw std::runtime_error("not supported"); - return -1; - } -}; -} -} -} diff --git a/src/tunnel/detail/platform_unsupported/stack_tap_interface.hpp b/src/tunnel/detail/platform_unsupported/stack_tap_interface.hpp deleted file mode 100644 index 679d8da..0000000 --- a/src/tunnel/detail/platform_unsupported/stack_tap_interface.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include "layer_tap.hpp" - -#include "../layer_final.hpp" -#include "../layer_monitor.hpp" -namespace tunnel -{ -namespace detail -{ -namespace platform_unsupported -{ -// clang-format off -struct stack_tap_interface : public - layer_tap< - layer_monitor< - layer_final>> -// clang-format on -{ - static bool is_platform_supported() - { - return false; - } - - static auto type() -> std::string - { - return "tunnel::detail::platform_unsupported::stack_tap_interface"; - } -}; - -} -} -} diff --git a/src/tunnel/detail/platform_unsupported/stack_tun_interface.hpp b/src/tunnel/detail/platform_unsupported/stack_tun_interface.hpp deleted file mode 100644 index c9d214d..0000000 --- a/src/tunnel/detail/platform_unsupported/stack_tun_interface.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include "layer_tun.hpp" - -#include "../layer_final.hpp" -#include "../layer_monitor.hpp" -namespace tunnel -{ -namespace detail -{ -namespace platform_unsupported -{ -// clang-format off -struct stack_tun_interface : public - layer_tun< - layer_monitor< - layer_final>> -// clang-format on -{ - static bool is_platform_supported() - { - return false; - } - - static auto type() -> std::string - { - return "tunnel::detail::platform_unsupported::stack_tun_interface"; - } -}; - -} -} -} diff --git a/src/tunnel/detail/platform_unsupported/layer_tun.hpp b/src/tunnel/detail/platform_unsupported/unsupported.hpp similarity index 54% rename from src/tunnel/detail/platform_unsupported/layer_tun.hpp rename to src/tunnel/detail/platform_unsupported/unsupported.hpp index e2506c5..fdef87f 100644 --- a/src/tunnel/detail/platform_unsupported/layer_tun.hpp +++ b/src/tunnel/detail/platform_unsupported/unsupported.hpp @@ -5,188 +5,178 @@ #pragma once -#include -#include - -#include "../../interface_config.hpp" -#include "../../log_level.hpp" -#include "../log_kind.hpp" - +#include "../../interface.hpp" +#include "../monitor.hpp" namespace tunnel { namespace detail { namespace platform_unsupported { -template -class layer_tun : public Super +struct unsupported { -public: - void create(const config& config, std::error_code& error) + unsupported() : m_impl("unsupported", {}) { - Super::do_log(log_level::error, log_kind::unsupported_platform); - error = std::make_error_code(std::errc::not_supported); } - void rename(const std::string& interface_name, std::error_code& error) const + void create(const tunnel::interface::config&, std::error_code& error) { - (void)interface_name; - - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } - void set_owner(const std::string& owner, std::error_code& error) const + void rename(const std::string&, std::error_code& error) const { - (void)owner; + error = std::make_error_code(std::errc::not_supported); + } - Super::do_log(log_level::error, log_kind::unsupported_platform); + void set_owner(const std::string&, std::error_code& error) const + { error = std::make_error_code(std::errc::not_supported); } - void set_group(const std::string& group, std::error_code& error) const + void set_group(const std::string&, std::error_code& error) const { - (void)group; - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } std::string owner(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } std::string group(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } std::string interface_name(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } bool is_up(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return false; } bool is_down(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return false; } void up(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } void down(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } bool is_persistent(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return false; } void set_persistent(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } int mtu(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return 0; } void set_non_persistent(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } - void set_mtu(int mtu, std::error_code& error) const + void set_mtu(int, std::error_code& error) const { - (void)mtu; - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } - void set_ipv4(const std::string& address, std::error_code& error) const + void set_ipv4(const std::string&, std::error_code& error) const { - (void)address; - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } void enable_default_route(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } void disable_default_route(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } bool is_default_route(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return false; } std::string ipv4(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } std::string ipv4_netmask(std::error_code& error) const { - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); return ""; } - void set_ipv4_netmask(const std::string& netmask, - std::error_code& error) const + void set_ipv4_netmask(const std::string&, std::error_code& error) const { - (void)netmask; - - Super::do_log(log_level::error, log_kind::unsupported_platform); error = std::make_error_code(std::errc::not_supported); } int native_handle() const { - Super::do_log(log_level::error, log_kind::unsupported_platform); throw std::runtime_error("not supported"); return -1; } + + auto monitor() -> tunnel::monitor& + { + throw std::runtime_error("not supported"); + return m_impl; + } + + auto monitor() const -> const tunnel::monitor& + { + throw std::runtime_error("not supported"); + return m_impl; + } + + void set_log_callback(const tunnel::log_callback&) + { + throw std::runtime_error("not supported"); + } + + void enable_log(log_level = log_level::state, std::string = "", + std::string = "", std::any = {}) + { + throw std::runtime_error("not supported"); + } + +private: + tunnel::detail::monitor m_impl; }; + } } } diff --git a/src/tunnel/detail/platform_linux/scoped_file_descriptor.hpp b/src/tunnel/detail/scoped_file_descriptor.hpp similarity index 99% rename from src/tunnel/detail/platform_linux/scoped_file_descriptor.hpp rename to src/tunnel/detail/scoped_file_descriptor.hpp index 1262260..53c8a7a 100644 --- a/src/tunnel/detail/platform_linux/scoped_file_descriptor.hpp +++ b/src/tunnel/detail/scoped_file_descriptor.hpp @@ -12,8 +12,6 @@ namespace tunnel { namespace detail { -namespace platform_linux -{ /// RAII (Resource Allocation Is Initialization) wrapper for a file /// descriptor. Ensures that the file descriptor gets closed. // template @@ -100,4 +98,3 @@ class scoped_file_descriptor } } -} diff --git a/src/tunnel/detail/to_string.cpp b/src/tunnel/detail/to_string.cpp index 64df35f..bf7b82c 100644 --- a/src/tunnel/detail/to_string.cpp +++ b/src/tunnel/detail/to_string.cpp @@ -51,12 +51,18 @@ auto to_string(log_kind kind) -> std::string return "interface_mtu"; case log_kind::set_mtu: return "set_mtu"; - case log_kind::interface_ipv4: - return "interface_ipv4_address"; + case log_kind::is_default_route: + return "is_default_route"; + case log_kind::enable_default_route: + return "enable_default_route"; + case log_kind::disable_default_route: + return "disable_default_route"; + case log_kind::ipv4: + return "ipv4"; + case log_kind::ipv4_netmask: + return "ipv4_netmask"; case log_kind::set_ipv4: - return "set_ipv4_address"; - case log_kind::interface_ipv4_netmask: - return "interface_ipv4_netmask"; + return "set_ipv4"; case log_kind::set_ipv4_netmask: return "set_ipv4_netmask"; case log_kind::make_sockaddr: diff --git a/src/tunnel/tap_interface.cpp b/src/tunnel/interface.cpp similarity index 55% rename from src/tunnel/tap_interface.cpp rename to src/tunnel/interface.cpp index 0070003..7fbfc65 100644 --- a/src/tunnel/tap_interface.cpp +++ b/src/tunnel/interface.cpp @@ -1,60 +1,57 @@ - // Copyright (c) 2017 Steinwurf ApS // All Rights Reserved // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -// clang-format off -#include "throw_if_error.hpp" -#include "tap_interface.hpp" -// clang-format on - #include +#include "interface.hpp" +#include "throw_if_error.hpp" + #include #if defined(PLATFORM_LINUX) - -#include "detail/platform_linux/stack_tap_interface.hpp" -using platform_tap_interface = - tunnel::detail::platform_linux::stack_tap_interface; - +#include "detail/platform_linux/stack_interface.hpp" +using platform_interface = tunnel::detail::platform_linux::stack_interface; +static constexpr bool platform_supported = true; +#elif defined(PLATFORM_MAC) +#include "detail/platform_macos/interface.hpp" +using platform_interface = tunnel::detail::platform_macos::interface; +static constexpr bool platform_supported = true; #else - -#include "detail/platform_unsupported/stack_tap_interface.hpp" -using platform_tap_interface = - tunnel::detail::platform_unsupported::stack_tap_interface; - +#include "detail/platform_unsupported/unsupported.hpp" +using platform_interface = tunnel::detail::platform_unsupported::unsupported; +static constexpr bool platform_supported = false; #endif namespace tunnel { -struct tap_interface::impl : platform_tap_interface +struct interface::impl : platform_interface { }; -tap_interface::tap_interface() +interface::interface() { - m_impl = std::make_unique(); + m_impl = std::make_unique(); } -tap_interface::tap_interface(tap_interface&& iface) +interface::interface(interface&& iface) { m_impl = std::move(iface.m_impl); } -tap_interface& tap_interface::operator=(tap_interface&& iface) +interface& interface::operator=(interface&& iface) { m_impl = std::move(iface.m_impl); return *this; } -tap_interface::~tap_interface() +interface::~interface() { } -void tap_interface::create(const config& config) +void interface::create(const interface::config& config) { assert(m_impl); @@ -63,13 +60,13 @@ void tap_interface::create(const config& config) throw_if_error(error); } -void tap_interface::create(const config& config, std::error_code& error) +void interface::create(const interface::config& config, std::error_code& error) { assert(m_impl); m_impl->create(config, error); } -void tap_interface::rename(const std::string& interface_name) const +void interface::rename(const std::string& interface_name) const { assert(m_impl); @@ -78,14 +75,14 @@ void tap_interface::rename(const std::string& interface_name) const throw_if_error(error); } -void tap_interface::rename(const std::string& interface_name, - std::error_code& error) const +void interface::rename(const std::string& interface_name, + std::error_code& error) const { assert(m_impl); m_impl->rename(interface_name, error); } -auto tap_interface::owner() const -> std::string +auto interface::owner() const -> std::string { assert(m_impl); @@ -94,13 +91,13 @@ auto tap_interface::owner() const -> std::string throw_if_error(error); return own; } -auto tap_interface::owner(std::error_code& error) const -> std::string +auto interface::owner(std::error_code& error) const -> std::string { assert(m_impl); return m_impl->owner(error); } -auto tap_interface::group() const -> std::string +auto interface::group() const -> std::string { assert(m_impl); @@ -109,13 +106,13 @@ auto tap_interface::group() const -> std::string throw_if_error(error); return grp; } -auto tap_interface::group(std::error_code& error) const -> std::string +auto interface::group(std::error_code& error) const -> std::string { assert(m_impl); return m_impl->group(error); } -void tap_interface::set_owner(const std::string& owner) const +void interface::set_owner(const std::string& owner) const { assert(m_impl); @@ -123,14 +120,14 @@ void tap_interface::set_owner(const std::string& owner) const set_owner(owner, error); throw_if_error(error); } -void tap_interface::set_owner(const std::string& owner, - std::error_code& error) const +void interface::set_owner(const std::string& owner, + std::error_code& error) const { assert(m_impl); m_impl->set_owner(owner, error); } -void tap_interface::set_group(const std::string& group) const +void interface::set_group(const std::string& group) const { assert(m_impl); @@ -138,14 +135,14 @@ void tap_interface::set_group(const std::string& group) const set_group(group, error); throw_if_error(error); } -void tap_interface::set_group(const std::string& group, - std::error_code& error) const +void interface::set_group(const std::string& group, + std::error_code& error) const { assert(m_impl); m_impl->set_group(group, error); } -auto tap_interface::interface_name() const -> std::string +auto interface::interface_name() const -> std::string { assert(m_impl); @@ -155,19 +152,19 @@ auto tap_interface::interface_name() const -> std::string return name; } -auto tap_interface::interface_name(std::error_code& error) const -> std::string +auto interface::interface_name(std::error_code& error) const -> std::string { assert(m_impl); return m_impl->interface_name(error); } -auto tap_interface::is_persistent(std::error_code& error) const -> bool +auto interface::is_persistent(std::error_code& error) const -> bool { assert(m_impl); return m_impl->is_persistent(error); } -auto tap_interface::is_persistent() const -> bool +auto interface::is_persistent() const -> bool { assert(m_impl); @@ -177,13 +174,13 @@ auto tap_interface::is_persistent() const -> bool return persistent; } -auto tap_interface::is_up(std::error_code& error) const -> bool +auto interface::is_up(std::error_code& error) const -> bool { assert(m_impl); return m_impl->is_up(error); } -auto tap_interface::is_up() const -> bool +auto interface::is_up() const -> bool { assert(m_impl); @@ -193,13 +190,13 @@ auto tap_interface::is_up() const -> bool return up; } -auto tap_interface::is_down(std::error_code& error) const -> bool +auto interface::is_down(std::error_code& error) const -> bool { assert(m_impl); return m_impl->is_down(error); } -auto tap_interface::is_down() const -> bool +auto interface::is_down() const -> bool { assert(m_impl); @@ -209,7 +206,7 @@ auto tap_interface::is_down() const -> bool return down; } -void tap_interface::up() const +void interface::up() const { assert(m_impl); @@ -217,13 +214,13 @@ void tap_interface::up() const up(error); throw_if_error(error); } -void tap_interface::up(std::error_code& error) const +void interface::up(std::error_code& error) const { assert(m_impl); return m_impl->up(error); } -void tap_interface::down() const +void interface::down() const { assert(m_impl); @@ -231,24 +228,24 @@ void tap_interface::down() const down(error); throw_if_error(error); } -void tap_interface::down(std::error_code& error) const +void interface::down(std::error_code& error) const { assert(m_impl); return m_impl->down(error); } -void tap_interface::set_persistent(std::error_code& error) +void interface::set_persistent(std::error_code& error) { assert(m_impl); m_impl->set_persistent(error); } -void tap_interface::set_non_persistent(std::error_code& error) +void interface::set_non_persistent(std::error_code& error) { assert(m_impl); m_impl->set_non_persistent(error); } -void tap_interface::set_persistent() +void interface::set_persistent() { assert(m_impl); @@ -256,7 +253,7 @@ void tap_interface::set_persistent() m_impl->set_persistent(error); throw_if_error(error); } -void tap_interface::set_non_persistent() +void interface::set_non_persistent() { assert(m_impl); @@ -265,7 +262,7 @@ void tap_interface::set_non_persistent() throw_if_error(error); } -auto tap_interface::mtu() const -> uint32_t +auto interface::mtu() const -> uint32_t { assert(m_impl); @@ -275,13 +272,13 @@ auto tap_interface::mtu() const -> uint32_t return mtu; } -auto tap_interface::mtu(std::error_code& error) const -> uint32_t +auto interface::mtu(std::error_code& error) const -> uint32_t { assert(m_impl); return m_impl->mtu(error); } -void tap_interface::set_mtu(uint32_t mtu) const +void interface::set_mtu(uint32_t mtu) const { assert(m_impl); @@ -289,13 +286,13 @@ void tap_interface::set_mtu(uint32_t mtu) const set_mtu(mtu, error); throw_if_error(error); } -void tap_interface::set_mtu(uint32_t mtu, std::error_code& error) const +void interface::set_mtu(uint32_t mtu, std::error_code& error) const { assert(m_impl); m_impl->set_mtu(mtu, error); } -void tap_interface::enable_default_route() const +void interface::enable_default_route() const { assert(m_impl); @@ -303,13 +300,13 @@ void tap_interface::enable_default_route() const enable_default_route(error); throw_if_error(error); } -void tap_interface::enable_default_route(std::error_code& error) const +void interface::enable_default_route(std::error_code& error) const { assert(m_impl); m_impl->enable_default_route(error); } -void tap_interface::disable_default_route() const +void interface::disable_default_route() const { assert(m_impl); @@ -317,13 +314,13 @@ void tap_interface::disable_default_route() const disable_default_route(error); throw_if_error(error); } -void tap_interface::disable_default_route(std::error_code& error) const +void interface::disable_default_route(std::error_code& error) const { assert(m_impl); m_impl->disable_default_route(error); } -auto tap_interface::is_default_route() const -> bool +auto interface::is_default_route() const -> bool { assert(m_impl); @@ -333,13 +330,13 @@ auto tap_interface::is_default_route() const -> bool return is_default; } -auto tap_interface::is_default_route(std::error_code& error) const -> bool +auto interface::is_default_route(std::error_code& error) const -> bool { assert(m_impl); return m_impl->is_default_route(error); } -auto tap_interface::ipv4() const -> std::string +auto interface::ipv4() const -> std::string { assert(m_impl); @@ -349,13 +346,13 @@ auto tap_interface::ipv4() const -> std::string return ip; } -auto tap_interface::ipv4(std::error_code& error) const -> std::string +auto interface::ipv4(std::error_code& error) const -> std::string { assert(m_impl); return m_impl->ipv4(error); } -auto tap_interface::ipv4_netmask() const -> std::string +auto interface::ipv4_netmask() const -> std::string { assert(m_impl); @@ -365,13 +362,13 @@ auto tap_interface::ipv4_netmask() const -> std::string return ip; } -auto tap_interface::ipv4_netmask(std::error_code& error) const -> std::string +auto interface::ipv4_netmask(std::error_code& error) const -> std::string { assert(m_impl); return m_impl->ipv4_netmask(error); } -void tap_interface::set_ipv4(const std::string& ip) const +void interface::set_ipv4(const std::string& ip) const { assert(m_impl); @@ -379,14 +376,13 @@ void tap_interface::set_ipv4(const std::string& ip) const set_ipv4(ip, error); throw_if_error(error); } -void tap_interface::set_ipv4(const std::string& ip, - std::error_code& error) const +void interface::set_ipv4(const std::string& ip, std::error_code& error) const { assert(m_impl); m_impl->set_ipv4(ip, error); } -void tap_interface::set_ipv4_netmask(const std::string& mask) const +void interface::set_ipv4_netmask(const std::string& mask) const { assert(m_impl); @@ -395,40 +391,40 @@ void tap_interface::set_ipv4_netmask(const std::string& mask) const throw_if_error(error); } -void tap_interface::set_ipv4_netmask(const std::string& mask, - std::error_code& error) const +void interface::set_ipv4_netmask(const std::string& mask, + std::error_code& error) const { assert(m_impl); m_impl->set_ipv4_netmask(mask, error); } -auto tap_interface::native_handle() const -> int +auto interface::native_handle() const -> int { assert(m_impl); return m_impl->native_handle(); } -auto tap_interface::monitor() const -> const tunnel::monitor& +auto interface::monitor() const -> const tunnel::monitor& { assert(m_impl); return m_impl->monitor(); } -auto tap_interface::monitor() -> tunnel::monitor& +auto interface::monitor() -> tunnel::monitor& { assert(m_impl); return m_impl->monitor(); } -auto tap_interface::set_log_callback(const log_callback& callback) -> void +auto interface::set_log_callback(const log_callback& callback) -> void { assert(m_impl); m_impl->set_log_callback(callback); } -auto tap_interface::is_platform_supported() -> bool +auto interface::is_platform_supported() -> bool { - return platform_tap_interface::is_platform_supported(); + return platform_supported; } } diff --git a/src/tunnel/tun_interface.hpp b/src/tunnel/interface.hpp similarity index 86% rename from src/tunnel/tun_interface.hpp rename to src/tunnel/interface.hpp index 3328826..f0487ca 100644 --- a/src/tunnel/tun_interface.hpp +++ b/src/tunnel/interface.hpp @@ -6,32 +6,70 @@ #pragma once #include +#include #include #include -#include "interface_config.hpp" #include "monitor.hpp" namespace tunnel { -class tun_interface +class interface { - +public: + enum class type + { + tun, + tap + }; + +#if defined(PLATFORM_LINUX) + struct config + { + /// The mode of the interface + type interface_type = type::tun; + + /// The name of the interface + std::string interface_name; + + /// If true the interface will be created with + /// Virtual Network Device Header enabled. + bool vnet_hdr = false; + + /// If true the interface will be created with IFF_NO_PI enabled. + bool iff_no_pi = true; + }; +#elif defined(PLATFORM_MAC) + struct config + { + /// The mode of the interface + type interface_type = type::tun; + + // On MacOS we don't have any specific configuration (setting the name + // on macos is not possible) + }; +#else + struct config + { + /// The mode of the interface + type interface_type; + }; +#endif public: /// Constructor - tun_interface(); - tun_interface(tun_interface&&); - tun_interface& operator=(tun_interface&&); + interface(); + interface(interface&&); + interface& operator=(interface&&); /// Destructor - ~tun_interface(); + ~interface(); /// Create the interface - void create(const config& config); + void create(const interface::config& config); /// Create the interface /// @param the config for the interface - void create(const config& config, std::error_code& error); + void create(const interface::config& config, std::error_code& error); /// Rename the interface /// @param interface_name The new name of the interface @@ -86,7 +124,7 @@ class tun_interface /// @param error The error code in case of failure auto interface_name(std::error_code& error) const -> std::string; - /// @return The native file descriptor of the TUN interface. This + /// @return The native file descriptor of the interface. This /// can be used for reading and writing data to and from /// the interface. auto native_handle() const -> int; diff --git a/src/tunnel/interface_config.hpp b/src/tunnel/interface_config.hpp deleted file mode 100644 index 3afef18..0000000 --- a/src/tunnel/interface_config.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include -#include - -#if defined(PLATFORM_LINUX) -struct config -{ - /// The name of the interface - std::string interface_name; - - /// If true the interface will be created with Virtual Network - /// Device Header enabled. - bool vnet_hdr = false; - - /// If true the interface will be created with IFF_NO_PI enabled. - bool iff_no_pi = true; -}; -#elif defined(PLATFORM_MAC) -struct config -{ - // On MacOS we don't have any specific configuration (setting the name on - // macos is not possible) -}; - -#else -struct config -{ - /// The name of the interface - std::string interface_name; -}; - -#endif diff --git a/src/tunnel/tap_interface.hpp b/src/tunnel/tap_interface.hpp deleted file mode 100644 index 0ebb4eb..0000000 --- a/src/tunnel/tap_interface.hpp +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#pragma once - -#include -#include -#include - -#include "interface_config.hpp" -#include "monitor.hpp" - -namespace tunnel -{ -class tap_interface -{ - -public: - /// Constructor - tap_interface(); - tap_interface(tap_interface&&); - tap_interface& operator=(tap_interface&&); - - /// Destructor - ~tap_interface(); - - /// Create the interface - void create(const config& config); - - /// Create the interface - /// @param the config for the interface - void create(const config& config, std::error_code& error); - - /// Rename the interface - /// @param interface_name The new name of the interface - void rename(const std::string& interface_name) const; - - /// Rename the interface - /// @param interface_name The new name of the interface - /// @param error The error code in case of failure - void rename(const std::string& interface_name, - std::error_code& error) const; - - /// Set the owner of the interface - /// @param owner The owner of the interface - void set_owner(const std::string& owner) const; - - /// Set the owner of the interface - /// @param owner The owner of the interface - /// @param error The error code in case of failure - void set_owner(const std::string& owner, std::error_code& error) const; - - /// Set the group the interface belongs to - /// @param group The group the interface belongs to - void set_group(const std::string& group) const; - - /// Set the group the interface belongs to - /// @param group The group the interface belongs to - /// @param error The error code in case of failure - void set_group(const std::string& group, std::error_code& error) const; - - /// @return The owner of the interface or an empty string if no - /// is specified. - auto owner() const -> std::string; - - /// @return The owner of the interface or an empty string if no - /// is specified. - /// @param error The error code in case of failure - auto owner(std::error_code& error) const -> std::string; - - /// @return The group of the interface belongs to or an empty - /// string if no group is specified. - auto group() const -> std::string; - - /// @return The group of the interface belongs to or an empty - /// string if no group is specified. - /// @param error The error code in case of failure - auto group(std::error_code& error) const -> std::string; - - /// @return The interface name - auto interface_name() const -> std::string; - - /// @return The interface name - /// @param error The error code in case of failure - auto interface_name(std::error_code& error) const -> std::string; - - /// @return The native file descriptor of the TUN interface. This - /// can be used for reading and writing data to and from - /// the interface. - auto native_handle() const -> int; - - /// @return True if the interface is up - auto is_up() const -> bool; - - /// @return True if the interface is up - /// @param error The error code in case of failure - auto is_up(std::error_code& error) const -> bool; - - /// Set the interface up - void up() const; - - /// Set the interface up - /// @param error The error code in case of failure - void up(std::error_code& error) const; - - /// @return True if the interface is down - auto is_down() const -> bool; - - /// @return True if the interface is down - /// @param error The error code in case of failure - auto is_down(std::error_code& error) const -> bool; - - /// Set the interface down - void down() const; - - /// Set the interface down - /// @param error The error code in case of failure - void down(std::error_code& error) const; - - /// @return true if the interface is persistent - auto is_persistent() const -> bool; - - /// @return true if the interface is persistent - /// @param error The error code in case of failure - auto is_persistent(std::error_code& error) const -> bool; - - /// Change the persistent status - if persistent the interface - /// will not disappear when the application closes. - void set_persistent(); - - /// Change the persistent status - if persistent the interface - /// will not disappear when the application closes. - /// @param error The error code in case of failure - void set_persistent(std::error_code& error); - - /// Set the interface non-persistent, i.e., the interface will only - /// be around for as long as the application keeps it alive. - void set_non_persistent(); - - /// Set the interface non-persistent, i.e., the interface will only - /// be around for as long as the application keeps it alive. - /// @param error The error code in case of failure - void set_non_persistent(std::error_code& error); - - /// @return The MTU (Maximum Transfer Unit) of the interface - auto mtu() const -> uint32_t; - - /// @return The MTU (Maximum Transfer Unit) of the interface - /// @param error The error code in case of failure - auto mtu(std::error_code& error) const -> uint32_t; - - /// Set the MTU (Maximum Transfer Unit) of the interface - /// @param mtu The new MTU - void set_mtu(uint32_t mtu) const; - - /// Set the MTU (Maximum Transfer Unit) of the interface - /// @param mtu The new MTU - /// @param error The error code in case of failure - void set_mtu(uint32_t mtu, std::error_code& error) const; - - /// Check if the interface is the default route - auto is_default_route() const -> bool; - - /// Check if the interface is the default route - /// @param error The error code in case of failure - auto is_default_route(std::error_code& error) const -> bool; - - /// Enable default route for this interface - void enable_default_route() const; - - /// Enable default route for this interface - /// @param error The error code in case of failure - void enable_default_route(std::error_code& error) const; - - /// Disable default route for this interface - void disable_default_route() const; - - /// Disable default route for this interface - /// @param error The error code in case of failure - void disable_default_route(std::error_code& error) const; - - /// @return The IPv4 address for the interface - auto ipv4() const -> std::string; - - /// @return The IPv4 address for the interface - /// @param error The error code in case of failure - auto ipv4(std::error_code& error) const -> std::string; - - /// @return The IPv4 netmask of the interface - auto ipv4_netmask() const -> std::string; - - /// @return The IPv4 netmask of the interface - /// @param error The error code in case of failure - auto ipv4_netmask(std::error_code& error) const -> std::string; - - /// Set the IPv4 address of the interface. - /// @param ip The new IPv4 address - void set_ipv4(const std::string& ip) const; - - /// Set the IPv4 address of the interface. - /// @param ip The new IPv4 address - /// @param error The error code in case of failure - void set_ipv4(const std::string& ip, std::error_code& error) const; - - /// Set the IPv4 netmask - /// @param mask The new IPv4 netmask - void set_ipv4_netmask(const std::string& mask) const; - - /// Set the IPv4 netmask - /// @param mask The new IPv4 netmask - /// @param error The error code in case of failure - void set_ipv4_netmask(const std::string& mask, - std::error_code& error) const; - - /// @return The monitor for the interface - auto monitor() const -> const tunnel::monitor&; - - /// @return The monitor for the interface - auto monitor() -> tunnel::monitor&; - - /// Set the log callback - /// @param callback The log callback - void set_log_callback(const tunnel::log_callback& callback); - - /// Return true if the platform is supported, otherwise false - static auto is_platform_supported() -> bool; - -private: - struct impl; - std::unique_ptr m_impl; -}; -} diff --git a/src/tunnel/tun_interface.cpp b/src/tunnel/tun_interface.cpp deleted file mode 100644 index a3b81f5..0000000 --- a/src/tunnel/tun_interface.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright (c) 2017 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -// clang-format off -#include "throw_if_error.hpp" -#include "tun_interface.hpp" -// clang-format on - -#include - -#include - -#if defined(PLATFORM_LINUX) - -#include "detail/platform_linux/stack_tun_interface.hpp" -using platform_tun_interface = - tunnel::detail::platform_linux::stack_tun_interface; - -#elif defined(PLATFORM_MAC) - -#include "detail/platform_macos/tun_interface.hpp" -using platform_tun_interface = tunnel::detail::platform_macos::tun_interface; - -#else - -#include "detail/platform_unsupported/stack_tun_interface.hpp" -using platform_tun_interface = - tunnel::detail::platform_unsupported::stack_tun_interface; - -#endif - -namespace tunnel -{ - -struct tun_interface::impl : platform_tun_interface -{ -}; - -tun_interface::tun_interface() -{ - m_impl = std::make_unique(); -} - -tun_interface::tun_interface(tun_interface&& iface) -{ - m_impl = std::move(iface.m_impl); -} - -tun_interface& tun_interface::operator=(tun_interface&& iface) -{ - m_impl = std::move(iface.m_impl); - return *this; -} - -tun_interface::~tun_interface() -{ -} - -void tun_interface::create(const config& config) -{ - assert(m_impl); - - std::error_code error; - create(config, error); - throw_if_error(error); -} - -void tun_interface::create(const config& config, std::error_code& error) -{ - assert(m_impl); - m_impl->create(config, error); -} - -void tun_interface::rename(const std::string& interface_name) const -{ - assert(m_impl); - - std::error_code error; - rename(interface_name, error); - throw_if_error(error); -} - -void tun_interface::rename(const std::string& interface_name, - std::error_code& error) const -{ - assert(m_impl); - m_impl->rename(interface_name, error); -} - -auto tun_interface::owner() const -> std::string -{ - assert(m_impl); - - std::error_code error; - std::string own = owner(error); - throw_if_error(error); - return own; -} -auto tun_interface::owner(std::error_code& error) const -> std::string -{ - assert(m_impl); - return m_impl->owner(error); -} - -auto tun_interface::group() const -> std::string -{ - assert(m_impl); - - std::error_code error; - std::string grp = group(error); - throw_if_error(error); - return grp; -} -auto tun_interface::group(std::error_code& error) const -> std::string -{ - assert(m_impl); - return m_impl->group(error); -} - -void tun_interface::set_owner(const std::string& owner) const -{ - assert(m_impl); - - std::error_code error; - set_owner(owner, error); - throw_if_error(error); -} -void tun_interface::set_owner(const std::string& owner, - std::error_code& error) const -{ - assert(m_impl); - m_impl->set_owner(owner, error); -} - -void tun_interface::set_group(const std::string& group) const -{ - assert(m_impl); - - std::error_code error; - set_group(group, error); - throw_if_error(error); -} -void tun_interface::set_group(const std::string& group, - std::error_code& error) const -{ - assert(m_impl); - m_impl->set_group(group, error); -} - -auto tun_interface::interface_name() const -> std::string -{ - assert(m_impl); - - std::error_code error; - std::string name = interface_name(error); - throw_if_error(error); - return name; -} - -auto tun_interface::interface_name(std::error_code& error) const -> std::string -{ - assert(m_impl); - return m_impl->interface_name(error); -} - -auto tun_interface::is_persistent(std::error_code& error) const -> bool -{ - assert(m_impl); - return m_impl->is_persistent(error); -} - -auto tun_interface::is_persistent() const -> bool -{ - assert(m_impl); - - std::error_code error; - bool persistent = m_impl->is_persistent(error); - throw_if_error(error); - return persistent; -} - -auto tun_interface::is_up(std::error_code& error) const -> bool -{ - assert(m_impl); - return m_impl->is_up(error); -} - -auto tun_interface::is_up() const -> bool -{ - assert(m_impl); - - std::error_code error; - bool up = m_impl->is_up(error); - throw_if_error(error); - return up; -} - -auto tun_interface::is_down(std::error_code& error) const -> bool -{ - assert(m_impl); - return m_impl->is_down(error); -} - -auto tun_interface::is_down() const -> bool -{ - assert(m_impl); - - std::error_code error; - bool down = m_impl->is_down(error); - throw_if_error(error); - return down; -} - -void tun_interface::up() const -{ - assert(m_impl); - - std::error_code error; - up(error); - throw_if_error(error); -} -void tun_interface::up(std::error_code& error) const -{ - assert(m_impl); - return m_impl->up(error); -} - -void tun_interface::down() const -{ - assert(m_impl); - - std::error_code error; - down(error); - throw_if_error(error); -} -void tun_interface::down(std::error_code& error) const -{ - assert(m_impl); - return m_impl->down(error); -} - -void tun_interface::set_persistent(std::error_code& error) -{ - assert(m_impl); - m_impl->set_persistent(error); -} -void tun_interface::set_non_persistent(std::error_code& error) -{ - assert(m_impl); - m_impl->set_non_persistent(error); -} - -void tun_interface::set_persistent() -{ - assert(m_impl); - - std::error_code error; - m_impl->set_persistent(error); - throw_if_error(error); -} -void tun_interface::set_non_persistent() -{ - assert(m_impl); - - std::error_code error; - m_impl->set_non_persistent(error); - throw_if_error(error); -} - -auto tun_interface::mtu() const -> uint32_t -{ - assert(m_impl); - - std::error_code error; - uint32_t mtu = m_impl->mtu(error); - throw_if_error(error); - return mtu; -} - -auto tun_interface::mtu(std::error_code& error) const -> uint32_t -{ - assert(m_impl); - return m_impl->mtu(error); -} - -void tun_interface::set_mtu(uint32_t mtu) const -{ - assert(m_impl); - - std::error_code error; - set_mtu(mtu, error); - throw_if_error(error); -} -void tun_interface::set_mtu(uint32_t mtu, std::error_code& error) const -{ - assert(m_impl); - m_impl->set_mtu(mtu, error); -} - -void tun_interface::enable_default_route() const -{ - assert(m_impl); - - std::error_code error; - enable_default_route(error); - throw_if_error(error); -} -void tun_interface::enable_default_route(std::error_code& error) const -{ - assert(m_impl); - m_impl->enable_default_route(error); -} - -void tun_interface::disable_default_route() const -{ - assert(m_impl); - - std::error_code error; - disable_default_route(error); - throw_if_error(error); -} -void tun_interface::disable_default_route(std::error_code& error) const -{ - assert(m_impl); - m_impl->disable_default_route(error); -} - -auto tun_interface::is_default_route() const -> bool -{ - assert(m_impl); - - std::error_code error; - bool is_default = is_default_route(error); - throw_if_error(error); - return is_default; -} - -auto tun_interface::is_default_route(std::error_code& error) const -> bool -{ - assert(m_impl); - return m_impl->is_default_route(error); -} - -auto tun_interface::ipv4() const -> std::string -{ - assert(m_impl); - - std::error_code error; - std::string ip = ipv4(error); - throw_if_error(error); - return ip; -} - -auto tun_interface::ipv4(std::error_code& error) const -> std::string -{ - assert(m_impl); - return m_impl->ipv4(error); -} - -auto tun_interface::ipv4_netmask() const -> std::string -{ - assert(m_impl); - - std::error_code error; - std::string ip = ipv4_netmask(error); - throw_if_error(error); - return ip; -} - -auto tun_interface::ipv4_netmask(std::error_code& error) const -> std::string -{ - assert(m_impl); - return m_impl->ipv4_netmask(error); -} - -void tun_interface::set_ipv4(const std::string& ip) const -{ - assert(m_impl); - - std::error_code error; - set_ipv4(ip, error); - throw_if_error(error); -} -void tun_interface::set_ipv4(const std::string& ip, - std::error_code& error) const -{ - assert(m_impl); - m_impl->set_ipv4(ip, error); -} - -void tun_interface::set_ipv4_netmask(const std::string& mask) const -{ - assert(m_impl); - - std::error_code error; - set_ipv4_netmask(mask, error); - throw_if_error(error); -} - -void tun_interface::set_ipv4_netmask(const std::string& mask, - std::error_code& error) const -{ - assert(m_impl); - m_impl->set_ipv4_netmask(mask, error); -} - -auto tun_interface::native_handle() const -> int -{ - assert(m_impl); - return m_impl->native_handle(); -} - -auto tun_interface::monitor() const -> const tunnel::monitor& -{ - assert(m_impl); - return m_impl->monitor(); -} - -auto tun_interface::monitor() -> tunnel::monitor& -{ - assert(m_impl); - return m_impl->monitor(); -} - -auto tun_interface::set_log_callback(const log_callback& callback) -> void -{ - assert(m_impl); - m_impl->set_log_callback(callback); -} - -auto tun_interface::is_platform_supported() -> bool -{ - return platform_tun_interface::is_platform_supported(); -} - -} diff --git a/test/src/detail/platform_macos/test_tun_interface.cpp b/test/src/detail/platform_linux/stack_interface.cpp similarity index 70% rename from test/src/detail/platform_macos/test_tun_interface.cpp rename to test/src/detail/platform_linux/stack_interface.cpp index fdc107d..8f448ad 100644 --- a/test/src/detail/platform_macos/test_tun_interface.cpp +++ b/test/src/detail/platform_linux/stack_interface.cpp @@ -3,4 +3,4 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include diff --git a/test/src/detail/platform_linux/tap_interface.cpp b/test/src/detail/platform_linux/tap_interface.cpp deleted file mode 100644 index f04a321..0000000 --- a/test/src/detail/platform_linux/tap_interface.cpp +++ /dev/null @@ -1,7 +0,0 @@ - -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#include diff --git a/test/src/detail/platform_linux/tun_interface.cpp b/test/src/detail/platform_linux/test_layer_interface.cpp similarity index 68% rename from test/src/detail/platform_linux/tun_interface.cpp rename to test/src/detail/platform_linux/test_layer_interface.cpp index 992313c..ef26e08 100644 --- a/test/src/detail/platform_linux/tun_interface.cpp +++ b/test/src/detail/platform_linux/test_layer_interface.cpp @@ -3,4 +3,4 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include diff --git a/test/src/detail/platform_linux/test_scoped_file_descriptor.cpp b/test/src/detail/platform_linux/test_scoped_file_descriptor.cpp index d330f15..dc06a53 100644 --- a/test/src/detail/platform_linux/test_scoped_file_descriptor.cpp +++ b/test/src/detail/platform_linux/test_scoped_file_descriptor.cpp @@ -3,4 +3,4 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include diff --git a/test/src/detail/platform_linux/test_layer_tun.cpp b/test/src/detail/platform_macos/test_interface.cpp similarity index 72% rename from test/src/detail/platform_linux/test_layer_tun.cpp rename to test/src/detail/platform_macos/test_interface.cpp index 2de2cb3..4eddfda 100644 --- a/test/src/detail/platform_linux/test_layer_tun.cpp +++ b/test/src/detail/platform_macos/test_interface.cpp @@ -3,4 +3,4 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include diff --git a/test/src/detail/platform_unsupported/test_stack_tap_interface.cpp b/test/src/detail/platform_unsupported/test_stack_tap_interface.cpp deleted file mode 100644 index a233b72..0000000 --- a/test/src/detail/platform_unsupported/test_stack_tap_interface.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#include diff --git a/test/src/detail/platform_unsupported/test_stack_tun_interface.cpp b/test/src/detail/platform_unsupported/test_stack_tun_interface.cpp deleted file mode 100644 index 5a63779..0000000 --- a/test/src/detail/platform_unsupported/test_stack_tun_interface.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2017 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#include diff --git a/test/src/detail/platform_linux/test_layer_tap.cpp b/test/src/detail/platform_unsupported/test_unsupported.cpp similarity index 69% rename from test/src/detail/platform_linux/test_layer_tap.cpp rename to test/src/detail/platform_unsupported/test_unsupported.cpp index 521b659..dad4155 100644 --- a/test/src/detail/platform_linux/test_layer_tap.cpp +++ b/test/src/detail/platform_unsupported/test_unsupported.cpp @@ -3,4 +3,4 @@ // // Distributed under the "BSD License". See the accompanying LICENSE.rst file. -#include +#include diff --git a/test/src/test_interface.cpp b/test/src/test_interface.cpp new file mode 100644 index 0000000..6399137 --- /dev/null +++ b/test/src/test_interface.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2024 Steinwurf ApS +// All Rights Reserved +// +// Distributed under the "BSD License". See the accompanying LICENSE.rst file. + +#include +#include +#include + +TEST(test_interface, construct_no_su_fail) +{ + tunnel::interface t; + (void)t; +} + +#if defined(PLATFORM_LINUX) +TEST(test_interface, create_no_su_expect_fail) +{ + // Check if we are root + if (getuid() == 0) + { + GTEST_SKIP(); + } + tunnel::interface t; + EXPECT_THROW(t.create({tunnel::interface::type::tap, "dummy", false}), + std::system_error); + EXPECT_THROW(t.create({tunnel::interface::type::tap, "dummy", true}), + std::system_error); + EXPECT_THROW(t.create({tunnel::interface::type::tap, + "too_long_name_way_over_20_chars", false}), + std::system_error); + + EXPECT_THROW(t.create({tunnel::interface::type::tun, "dummy", false}), + std::system_error); + EXPECT_THROW(t.create({tunnel::interface::type::tun, "dummy", true}), + std::system_error); + EXPECT_THROW(t.create({tunnel::interface::type::tun, + "too_long_name_way_over_20_chars", false}), + std::system_error); +} +#elif defined(PLATFORM_MAC) +TEST(test_interface, create_no_su_expect_fail) +{ + // Check if we are root + if (getuid() == 0) + { + GTEST_SKIP(); + } + tunnel::interface t; + EXPECT_THROW(t.create({}), std::system_error); +} +#endif + +#if defined(PLATFORM_LINUX) || defined(PLATFORM_MAC) +TEST(test_interface, options) +{ + if (getuid() != 0) + { + GTEST_SKIP(); + } + const auto ip_addr = "192.168.60.1"; + const auto netmask = "255.255.0.0"; + const uint32_t mtu = 1500; + tunnel::interface t; + t.create({}); + t.up(); + t.set_mtu(1500); + EXPECT_EQ(t.mtu(), mtu); + t.set_ipv4(ip_addr); + EXPECT_EQ(t.ipv4(), ip_addr); + t.set_ipv4_netmask(netmask); + EXPECT_EQ(t.ipv4_netmask(), netmask); + t.enable_default_route(); + t.disable_default_route(); + t.down(); +} +#endif diff --git a/test/src/test_tap_interface.cpp b/test/src/test_tap_interface.cpp deleted file mode 100644 index 57cd38e..0000000 --- a/test/src/test_tap_interface.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2024 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#include -#include -#include - -#if defined(PLATFORM_LINUX) -TEST(test_tap_interface, construct_no_su_fail) -{ - tunnel::tap_interface t; - (void)t; -} - -TEST(test_tap_interface, create_no_su_expect_fail) -{ - // Check if we are root - if (getuid() != 0) - { - tunnel::tap_interface t; - EXPECT_THROW(t.create({"dummy", false}), std::system_error); - EXPECT_THROW(t.create({"dummy", true}), std::system_error); - EXPECT_THROW(t.create({"too_long_name_way_over_20_chars", false}), - std::system_error); - } -} - -#endif diff --git a/test/src/test_tun_interface.cpp b/test/src/test_tun_interface.cpp deleted file mode 100644 index 2e3887c..0000000 --- a/test/src/test_tun_interface.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2017 Steinwurf ApS -// All Rights Reserved -// -// Distributed under the "BSD License". See the accompanying LICENSE.rst file. - -#include -#include -#include - -#if defined(PLATFORM_MAC) - -TEST(test_tun_interface, construct_no_su_fail) -{ - tunnel::tun_interface t; - (void)t; -} - -TEST(test_tun_interface, create_no_su_expect_fail) -{ - // Check if we are root - if (getuid() != 0) - { - tunnel::tun_interface t; - EXPECT_THROW(t.create({}), std::system_error); - } -} - -#elif defined(PLATFORM_LINUX) -TEST(test_tun_interface, construct_no_su_fail) -{ - tunnel::tun_interface t; - (void)t; -} - -TEST(test_tun_interface, create_no_su_expect_fail) -{ - // Check if we are root - if (getuid() != 0) - { - tunnel::tun_interface t; - EXPECT_THROW(t.create({"dummy", false}), std::system_error); - EXPECT_THROW(t.create({"dummy", true}), std::system_error); - EXPECT_THROW(t.create({"too_long_name_way_over_20_chars", false}), - std::system_error); - } -} -#endif -#if defined(PLATFORM_LINUX) || defined(PLATFORM_MAC) -TEST(test_tun_interface, options) -{ - uid_t uid = getuid(); - if (uid != 0) - { - GTEST_SKIP(); - } - const auto ip_addr = "192.168.60.1"; - const auto netmask = "255.255.0.0"; - const auto mtu = 1500; - tunnel::tun_interface t; - t.create({}); - t.up(); - t.set_mtu(1500); - EXPECT_EQ(t.mtu(), mtu); - t.set_ipv4(ip_addr); - EXPECT_EQ(t.ipv4(), ip_addr); - t.set_ipv4_netmask(netmask); - EXPECT_EQ(t.ipv4_netmask(), netmask); - t.enable_default_route(); - t.disable_default_route(); - t.down(); -} -#endif diff --git a/wscript b/wscript index 8bd45a7..8cab3f5 100644 --- a/wscript +++ b/wscript @@ -50,17 +50,17 @@ def build(bld): sources += bld.path.ant_glob("test/src/**/platform_linux/**/*.cpp") elif platform.system() == "Darwin": sources += bld.path.ant_glob("test/src/**/platform_macos/**/*.cpp") + sources += bld.path.ant_glob("test/src/**/platform_unsupported/**/*.cpp") bld.program( - features='cxx test', - source=['test/tunnel_tests.cpp'] + sources, - target='tunnel_tests', - use=['tunnel', 'gtest']) - - bld.recurse("examples") - bld.recurse("apps/app/") - - + features="cxx test", + source=["test/tunnel_tests.cpp"] + sources, + target="tunnel_tests", + use=["tunnel", "gtest"], + ) + if platform.system() == "Linux" or platform.system() == "Darwin": + bld.recurse("examples") + bld.recurse("apps/app/") class IntegrationContext(BuildContext): @@ -69,7 +69,7 @@ class IntegrationContext(BuildContext): def integration_test(ctx): - # Test only for linux platforms + # Test only for linux if not ctx.is_mkspec_platform("linux"): return