diff --git a/client/ovpncli.cpp b/client/ovpncli.cpp index 841143769..fe76225f2 100644 --- a/client/ovpncli.cpp +++ b/client/ovpncli.cpp @@ -1053,7 +1053,7 @@ OPENVPN_CLIENT_EXPORT Status OpenVPNClient::status_from_exception(const std::exc { Status ret; ret.error = true; - ret.message = Unicode::utf8_printable(e.what(), 256 | Unicode::UTF8_PASS_FMT); + ret.message = Unicode::utf8_printable(e.what(), 2048 | Unicode::UTF8_PASS_FMT); // if exception is an ExceptionCode, translate the code // to return status string diff --git a/deps/vcpkg-ports/mbedtls/portfile.cmake b/deps/vcpkg-ports/mbedtls/portfile.cmake new file mode 100644 index 000000000..cbed83c4e --- /dev/null +++ b/deps/vcpkg-ports/mbedtls/portfile.cmake @@ -0,0 +1,29 @@ +include(vcpkg_common_functions) + +set(VCPKG_LIBRARY_LINKAGE static) + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO ARMmbed/mbedtls + REF mbedtls-2.7.12 + SHA512 bfad5588804e52827ecba81ca030fe570c9772f633fbf470d71a781db4366541da69b85ee10941bf500a987c4da825caa049afc2c0e6ec0ecc55d50efd74e5a6 + HEAD_REF master + PATCHES + ../../mbedtls/patches/0001-relax-x509-date-format-check.patch +) + +vcpkg_configure_cmake( + SOURCE_PATH ${SOURCE_PATH} + PREFER_NINJA + OPTIONS + -DENABLE_TESTING=OFF + -DENABLE_PROGRAMS=OFF +) + +vcpkg_install_cmake() + +file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include) + +file(INSTALL ${SOURCE_PATH}/LICENSE DESTINATION ${CURRENT_PACKAGES_DIR}/share/mbedtls RENAME copyright) + +vcpkg_copy_pdbs() diff --git a/openvpn/addr/ip.hpp b/openvpn/addr/ip.hpp index e31ad2015..8a8763ba5 100644 --- a/openvpn/addr/ip.hpp +++ b/openvpn/addr/ip.hpp @@ -335,9 +335,9 @@ class Addr static Addr from_sockaddr(const struct sockaddr *sa) { if (sa->sa_family == AF_INET) - return from_ipv4(IPv4::Addr::from_sockaddr((struct sockaddr_in *)sa)); + return from_ipv4(IPv4::Addr::from_sockaddr(reinterpret_cast(sa))); else if (sa->sa_family == AF_INET6) - return from_ipv6(IPv6::Addr::from_sockaddr((struct sockaddr_in6 *)sa)); + return from_ipv6(IPv6::Addr::from_sockaddr(reinterpret_cast(sa))); else return Addr(); } diff --git a/openvpn/addr/ipv6.hpp b/openvpn/addr/ipv6.hpp index 864df55bb..3f5ec53e5 100644 --- a/openvpn/addr/ipv6.hpp +++ b/openvpn/addr/ipv6.hpp @@ -109,6 +109,10 @@ class Addr // NOTE: must be union-legal, so default constructor does not initial ret.sin6_port = htons(port); host_to_network_order((union ipv6addr *)&ret.sin6_addr.s6_addr, &u); ret.sin6_scope_id = scope_id_; +#ifdef SIN6_LEN + /* This is defined on both macOS and FreeBSD that have the sin6_len member */ + ret.sin6_len = sizeof(sockaddr_in6); +#endif return ret; } diff --git a/openvpn/client/cliopt.hpp b/openvpn/client/cliopt.hpp index fe87a2ef6..fb82fc82b 100644 --- a/openvpn/client/cliopt.hpp +++ b/openvpn/client/cliopt.hpp @@ -958,8 +958,8 @@ class ClientOptions : public RC "WSHOST", "WEB_CA_BUNDLE", "IS_OPENVPN_WEB_CA", - "OVPN_ACCESS_SERVER_NO_WEB", - }; + "NO_WEB", + "ORGANIZATION"}; std::unordered_set ignore_unknown_option_list; @@ -1069,6 +1069,19 @@ class ClientOptions : public RC if (pcc.pushPeerInfo()) { + /* If we override the HWADDR, we add it at this time statically. If we need to + * dynamically discover it from the transport it will be added in + * \c build_connect_time_peer_info_string instead */ + if (!config.clientconf.hwAddrOverride.empty()) + { + pi->emplace_back("IV_HWADDR", config.clientconf.hwAddrOverride); + } + + pi->emplace_back("IV_SSL", get_ssl_library_version()); + + if (!config.clientconf.platformVersion.empty()) + pi->emplace_back("IV_PLAT_VER", config.clientconf.platformVersion); + /* ensure that we use only one variable with the same name */ std::unordered_map extra_values; @@ -1106,19 +1119,6 @@ class ClientOptions : public RC if (!config.clientconf.appCustomProtocols.empty()) pi->emplace_back("IV_ACC", "2048,6:A," + config.clientconf.appCustomProtocols); - // MAC address - if (pcc.pushPeerInfo()) - { - std::string hwaddr = get_hwaddr(); - if (!config.clientconf.hwAddrOverride.empty()) - pi->emplace_back("IV_HWADDR", config.clientconf.hwAddrOverride); - else if (!hwaddr.empty()) - pi->emplace_back("IV_HWADDR", hwaddr); - pi->emplace_back("IV_SSL", get_ssl_library_version()); - - if (!config.clientconf.platformVersion.empty()) - pi->emplace_back("IV_PLAT_VER", config.clientconf.platformVersion); - } return pi; } @@ -1326,6 +1326,7 @@ class ClientOptions : public RC cp->load(opt, *proto_context_options, config.default_key_direction, false); cp->set_xmit_creds(!autologin || pcc.hasEmbeddedPassword() || autologin_sessions); cp->extra_peer_info = build_peer_info(config, pcc, autologin_sessions); + cp->extra_peer_info_push_peerinfo = pcc.pushPeerInfo(); cp->frame = frame; cp->now = &now_; cp->rng = rng; diff --git a/openvpn/client/cliopthelper.hpp b/openvpn/client/cliopthelper.hpp index ea0de9c77..2b065b4ad 100644 --- a/openvpn/client/cliopthelper.hpp +++ b/openvpn/client/cliopthelper.hpp @@ -367,8 +367,12 @@ class ParseClientConfig // add in missing options bool added = false; - // client - if (options.exists("tls-client") && options.exists("pull")) + /* client + Ensure that we always look at both options, so they register as touched */ + const bool tls_client_exists = options.exists("tls-client"); + const bool pull_exists = options.exists("pull"); + + if (tls_client_exists && pull_exists) { Option opt; opt.push_back("client"); diff --git a/openvpn/client/cliproto.hpp b/openvpn/client/cliproto.hpp index 2c99a6e89..c2d626364 100644 --- a/openvpn/client/cliproto.hpp +++ b/openvpn/client/cliproto.hpp @@ -508,6 +508,7 @@ class Session : ProtoContextCallbackInterface, { try { + proto_context.conf().build_connect_time_peer_info_string(transport); OPENVPN_LOG("Connecting to " << server_endpoint_render()); proto_context.set_protocol(transport->transport_protocol()); proto_context.start(); @@ -1131,7 +1132,7 @@ class Session : ProtoContextCallbackInterface, if (tls_warnings & SSLAPI::TLS_WARN_SIG_MD5) { - ClientEvent::Base::Ptr ev = new ClientEvent::Warn("TLS: received certificate signed with MD5. Please inform your admin to upgrade to a stronger algorithm. Support for MD5 will be dropped at end of Apr 2018"); + ClientEvent::Base::Ptr ev = new ClientEvent::Warn("TLS: received certificate signed with MD5. Please inform your admin to upgrade to a stronger algorithm. Support for MD5 will be dropped in the near future"); cli_events->add_event(std::move(ev)); } diff --git a/openvpn/dco/dcocli.hpp b/openvpn/dco/dcocli.hpp index ca76185b0..0e21c6bc1 100644 --- a/openvpn/dco/dcocli.hpp +++ b/openvpn/dco/dcocli.hpp @@ -36,22 +36,22 @@ #include #include -#ifndef ENABLE_OVPNDCOWIN +#if !defined(ENABLE_OVPNDCOWIN) #include #endif -#ifdef ENABLE_KOVPN +#if defined(ENABLE_KOVPN) #include #include #include #include -#elif ENABLE_OVPNDCO +#elif defined(ENABLE_OVPNDCO) #include #include #include #include #include -#elif ENABLE_OVPNDCOWIN +#elif defined(ENABLE_OVPNDCOWIN) #include #include #include @@ -92,7 +92,7 @@ class ClientConfig : public DCO, virtual void finalize(const bool disconnected) override { -#ifdef ENABLE_OVPNDCOWIN +#if defined(ENABLE_OVPNDCOWIN) if (disconnected) tun.tun_persist.reset(); #endif @@ -286,7 +286,7 @@ class Client : public TransportClient, uint32_t peer_id; }; -#ifdef ENABLE_KOVPN +#if defined(ENABLE_KOVPN) #include inline DCO::Ptr new_controller(TunBuilderBase *) { @@ -298,7 +298,7 @@ ClientConfig::new_transport_client_obj(openvpn_io::io_context &io_context, { return TransportClient::Ptr(new KovpnClient(io_context, this, parent)); } -#elif ENABLE_OVPNDCO +#elif defined(ENABLE_OVPNDCO) #include inline DCO::Ptr new_controller(TunBuilderBase *tb) { @@ -317,7 +317,7 @@ ClientConfig::new_transport_client_obj(openvpn_io::io_context &io_context, { return TransportClient::Ptr(new OvpnDcoClient(io_context, this, parent)); } -#elif ENABLE_OVPNDCOWIN +#elif defined(ENABLE_OVPNDCOWIN) #include inline DCO::Ptr new_controller(TunBuilderBase *tb) { diff --git a/openvpn/netconf/hwaddr.hpp b/openvpn/netconf/hwaddr.hpp index d0e27df0b..a9f3d32d5 100644 --- a/openvpn/netconf/hwaddr.hpp +++ b/openvpn/netconf/hwaddr.hpp @@ -32,13 +32,13 @@ #if defined(OPENVPN_PLATFORM_WIN) && !defined(OPENVPN_PLATFORM_UWP) #include #elif defined(OPENVPN_PLATFORM_MAC) -#include +#include #elif defined(TARGET_OS_IPHONE) #include #endif namespace openvpn { -inline std::string get_hwaddr() +inline std::string get_hwaddr([[maybe_unused]] IP::Addr server_addr) { #if defined(OPENVPN_PLATFORM_WIN) && !defined(OPENVPN_PLATFORM_UWP) const TunWin::Util::BestGateway dg{AF_INET}; @@ -53,7 +53,7 @@ inline std::string get_hwaddr() } } #elif defined(OPENVPN_PLATFORM_MAC) - const MacGatewayInfoV4 gw; + const MacGatewayInfo gw{server_addr}; if (gw.hwaddr_defined()) { const MACAddr &mac = gw.hwaddr(); diff --git a/openvpn/ssl/peerinfo.hpp b/openvpn/ssl/peerinfo.hpp index 70e873752..6646e97e4 100644 --- a/openvpn/ssl/peerinfo.hpp +++ b/openvpn/ssl/peerinfo.hpp @@ -90,6 +90,13 @@ struct Set : public std::vector, public RCCopyable #include #include +#include #include #include #include #include #include #include +#include #include #ifndef OPENVPN_DEBUG_PROTO @@ -412,6 +414,14 @@ class ProtoContext : public logging::LoggingMixincontains_key("IV_HWADDR")) + { + std::string hwaddr = get_hwaddr(transport->server_endpoint_addr()); + if (!hwaddr.empty()) + extra_peer_info_transport->emplace_back("IV_HWADDR", hwaddr); + } + } + } + // generate a string summarizing information about the client // including capabilities std::string peer_info_string() const @@ -1085,6 +1115,8 @@ class ProtoContext : public logging::LoggingMixinto_string(); + if (extra_peer_info_transport) + out << extra_peer_info_transport->to_string(); if (is_bs64_cipher(dc.cipher())) out << "IV_BS64DL=1\n"; // indicate support for data limits when using 64-bit block-size ciphers, version 1 (CVE-2016-6329) if (relay_mode) diff --git a/openvpn/tun/mac/gwv4.hpp b/openvpn/tun/mac/gw.hpp similarity index 63% rename from openvpn/tun/mac/gwv4.hpp rename to openvpn/tun/mac/gw.hpp index a19c79cf5..4db0dc6ab 100644 --- a/openvpn/tun/mac/gwv4.hpp +++ b/openvpn/tun/mac/gw.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -47,9 +48,10 @@ #include #include #include +#include namespace openvpn { -class MacGatewayInfoV4 +class MacGatewayInfo { struct rtmsg { @@ -60,12 +62,21 @@ class MacGatewayInfoV4 #define OPENVPN_ROUNDUP(a) \ ((a) > 0 ? (1 + (((a)-1) | (sizeof(std::uint32_t) - 1))) : sizeof(std::uint32_t)) -#define OPENVPN_NEXTADDR(w, u) \ - if (rtm_addrs & (w)) \ - { \ - l = OPENVPN_ROUNDUP(u.sa_len); \ - std::memmove(cp, &(u), l); \ - cp += l; \ +#define OPENVPN_NEXTADDR(w, u) \ + if (rtm_addrs & (w)) \ + { \ + l = OPENVPN_ROUNDUP(u.sin_len); \ + std::memmove(cp, &(u), l); \ + cp += l; \ + } + + +#define OPENVPN_NEXTADDR6(w, u) \ + if (rtm_addrs & (w)) \ + { \ + l = OPENVPN_ROUNDUP(u.sin6_len); \ + std::memmove(cp, &(u), l); \ + cp += l; \ } #define OPENVPN_ADVANCE(x, n) \ @@ -82,13 +93,13 @@ class MacGatewayInfoV4 IFACE_DEFINED = (1 << 3), /* set if iface is defined */ }; - MacGatewayInfoV4() - : flags_(0) + MacGatewayInfo(IP::Addr dest) { struct rtmsg m_rtmsg; ScopedFD sockfd; int seq, l, pid, rtm_addrs; - struct sockaddr so_dst, so_mask; + sockaddr_in so_dst{}, so_mask{}; + sockaddr_in6 so_dst6{}; char *cp = m_rtmsg.m_space; struct sockaddr *gate = nullptr, *ifp = nullptr, *sa; struct rt_msghdr *rtm_aux; @@ -99,8 +110,6 @@ class MacGatewayInfoV4 rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP; std::memset(&m_rtmsg, 0, sizeof(m_rtmsg)); - std::memset(&so_dst, 0, sizeof(so_dst)); - std::memset(&so_mask, 0, sizeof(so_mask)); std::memset(&m_rtmsg.m_rtm, 0, sizeof(struct rt_msghdr)); m_rtmsg.m_rtm.rtm_type = RTM_GET; @@ -109,13 +118,24 @@ class MacGatewayInfoV4 m_rtmsg.m_rtm.rtm_seq = ++seq; m_rtmsg.m_rtm.rtm_addrs = rtm_addrs; - so_dst.sa_family = AF_INET; - so_dst.sa_len = sizeof(struct sockaddr_in); - so_mask.sa_family = AF_INET; - so_mask.sa_len = sizeof(struct sockaddr_in); + const bool ipv6 = dest.is_ipv6(); - OPENVPN_NEXTADDR(RTA_DST, so_dst); - OPENVPN_NEXTADDR(RTA_NETMASK, so_mask); + if (!ipv6) + { + so_dst = dest.to_ipv4().to_sockaddr(); + // 32 netmask to lookup the route to the destination + so_mask.sin_family = AF_INET; + so_mask.sin_addr.s_addr = 0xffffffff; + so_mask.sin_len = sizeof(struct sockaddr_in); + + OPENVPN_NEXTADDR(RTA_DST, so_dst); + OPENVPN_NEXTADDR(RTA_NETMASK, so_mask); + } + else + { + so_dst6 = dest.to_ipv6().to_sockaddr(); + OPENVPN_NEXTADDR6(RTA_DST, so_dst6); + } m_rtmsg.m_rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; @@ -123,10 +143,12 @@ class MacGatewayInfoV4 sockfd.reset(socket(PF_ROUTE, SOCK_RAW, 0)); if (!sockfd.defined()) throw route_gateway_error("GDG: socket #1 failed"); + auto ret = ::write(sockfd(), (char *)&m_rtmsg, l); if (ret < 0) throw route_gateway_error("GDG: problem writing to routing socket: " + std::to_string(ret) - + " errno: " + std::to_string(errno) + " msg: " + strerror(errno)); + + " errno: " + std::to_string(errno) + " msg: " + ::strerror(errno)); + do { l = ::read(sockfd(), (char *)&m_rtmsg, sizeof(m_rtmsg)); @@ -158,7 +180,7 @@ class MacGatewayInfoV4 if (gate != nullptr) { /* get default gateway addr */ - gateway_.addr.reset_ipv4_from_uint32(ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr)); + gateway_.addr = IP::Addr::from_sockaddr(gate); if (!gateway_.addr.unspecified()) flags_ |= ADDR_DEFINED; @@ -176,94 +198,64 @@ class MacGatewayInfoV4 } } - /* get netmask of interface that owns default gateway */ - if (flags_ & IFACE_DEFINED) + /* get netmask of interface that owns default gateway. Querying the IPv6 netmask does not + * seem to work on my system (Arne), so it is disabled for now until we can figure out why it + * doesn't work */ + if (flags_ & IFACE_DEFINED && gateway_.addr.version() == IP::Addr::V4) { - struct ifreq ifr; + ifreq ifr{}; + sa_family_t sa_family; + + sa_family = AF_INET; + ifr.ifr_addr.sa_family = sa_family; + string::strncpynt(ifr.ifr_name, iface_, IFNAMSIZ); - sockfd.reset(socket(AF_INET, SOCK_DGRAM, 0)); + sockfd.reset(socket(sa_family, SOCK_DGRAM, 0)); if (!sockfd.defined()) throw route_gateway_error("GDG: socket #2 failed"); - std::memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_addr.sa_family = AF_INET; - string::strncpynt(ifr.ifr_name, iface_, IFNAMSIZ); - if (::ioctl(sockfd(), SIOCGIFNETMASK, (char *)&ifr) < 0) - throw route_gateway_error("GDG: ioctl #1 failed"); - sockfd.close(); + throw route_gateway_error("GDG: ioctl SIOCGIFNETMASK failed"); - gateway_.netmask.reset_ipv4_from_uint32(ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr)); + gateway_.netmask = IP::Addr::from_sockaddr(&ifr.ifr_addr); flags_ |= NETMASK_DEFINED; + + sockfd.close(); } /* try to read MAC addr associated with interface that owns default gateway */ if (flags_ & IFACE_DEFINED) { - struct ifconf ifc; - const int bufsize = 4096; + struct ifaddrs *ifaddrp, *ifa; - const std::unique_ptr buffer(new char[bufsize]); - std::memset(buffer.get(), 0, bufsize); - sockfd.reset(socket(AF_INET, SOCK_DGRAM, 0)); - if (!sockfd.defined()) - throw route_gateway_error("GDG: socket #3 failed"); - - ifc.ifc_len = bufsize; - ifc.ifc_buf = buffer.get(); + if (getifaddrs(&ifaddrp) != 0) + { + throw route_gateway_error("GDG: getifaddrs failed errno: " + std::to_string(errno) + " msg: " + ::strerror(errno)); + } - if (::ioctl(sockfd(), SIOCGIFCONF, (char *)&ifc) < 0) - throw route_gateway_error("GDG: ioctl #2 failed"); - sockfd.close(); + /* put the pointer into a unique_ptr to have RAII (allow throwing etc) */ + std::unique_ptr<::ifaddrs, decltype(&::freeifaddrs)> ifap{ifaddrp, &::freeifaddrs}; - for (cp = buffer.get(); cp <= buffer.get() + ifc.ifc_len - sizeof(struct ifreq);) + for (ifa = ifap.get(); ifa != nullptr; ifa = ifa->ifa_next) { - ifreq ifr = {}; - std::memcpy(&ifr, cp, sizeof(ifr)); - const size_t len = sizeof(ifr.ifr_name) + std::max(sizeof(ifr.ifr_addr), size_t{ifr.ifr_addr.sa_len}); + if (ifa->ifa_addr == nullptr) + continue; - if (!ifr.ifr_addr.sa_family) - break; - if (!::strncmp(ifr.ifr_name, iface_, IFNAMSIZ)) + if (flags_ & IFACE_DEFINED + && ifa->ifa_addr->sa_family == AF_LINK + && !strncmp(ifa->ifa_name, iface_, IFNAMSIZ)) { - if (ifr.ifr_addr.sa_family == AF_LINK) - { - /* This is a confusing member access on multiple levels. - * - * struct sockaddr_dl is 20 bytes in size and has - * 12 bytes space for the hw address (6 bytes) - * and Ethernet interface name (max 16 bytes) - * - * So if the interface name is more than 6 byte, it - * extends beyond the struct. - * - * This struct is embedded into ifreq that has - * 16 bytes for a sockaddr and also expects this - * struct to potentially extend beyond the bounds of - * the struct. - * - * Since we only copied 32 bytes from cp to ifr but sdl - * might extend after ifr's end, we need to copy from - * cp directly to avoid missing out on extra bytes - * behind the struct - */ - const size_t sock_dl_len = std::max(sizeof(sockaddr_dl), size_t{ifr.ifr_addr.sa_len}); - - const std::unique_ptr sock_dl_buf(new char[sock_dl_len]); - std::memcpy(sock_dl_buf.get(), cp + offsetof(struct ifreq, ifr_addr), sock_dl_len); - - const struct sockaddr_dl *sockaddr_dl = reinterpret_cast(sock_dl_buf.get()); - - hwaddr_.reset(reinterpret_cast(LLADDR(sockaddr_dl))); - flags_ |= HWADDR_DEFINED; - } + const struct sockaddr_dl *sockaddr_dl = reinterpret_cast(ifa->ifa_addr); + + hwaddr_.reset(reinterpret_cast(LLADDR(sockaddr_dl))); + flags_ |= HWADDR_DEFINED; } - cp += len; } } } #undef OPENVPN_ROUNDUP #undef OPENVPN_NEXTADDR +#undef OPENVPN_NEXTADDR6 #undef OPENVPN_ADVANCE std::string info() const @@ -325,7 +317,7 @@ class MacGatewayInfoV4 } private: - unsigned int flags_; + unsigned int flags_ = 0; IP::AddrMaskPair gateway_; char iface_[16]; MACAddr hwaddr_; diff --git a/test/ovpncli/cli.cpp b/test/ovpncli/cli.cpp index dab2aa663..358acf75c 100644 --- a/test/ovpncli/cli.cpp +++ b/test/ovpncli/cli.cpp @@ -1338,9 +1338,8 @@ int openvpn_client(int argc, char *argv[], const std::string *profile_content) else { #if defined(USE_NETCFG) - DBus conn(G_BUS_TYPE_SYSTEM); - conn.Connect(); - NetCfgTunBuilder client(conn.GetConnection()); + auto dbus_system = DBus::Connection::Create(DBus::BusType::SYSTEM); + NetCfgTunBuilder client(dbus_system); #else Client client; #endif diff --git a/test/unittests/test_cliopt.cpp b/test/unittests/test_cliopt.cpp index 0fcaaebad..2a3e6d87a 100644 --- a/test/unittests/test_cliopt.cpp +++ b/test/unittests/test_cliopt.cpp @@ -38,7 +38,15 @@ std::string minimalConfig = certconfig + "\n" + "client\n" "remote wooden.box\n"; -void load_client_config(const std::string &config_content, bool dco = false) +class ValidConfigs : public testing::TestWithParam +{ +}; +typedef std::pair config_error; +class InvalidConfigs : public testing::TestWithParam +{ +}; + +void load_client_config(const std::string &config_content) { OptionList options; ClientOptions::Config config; @@ -53,45 +61,38 @@ void load_client_config(const std::string &config_content, bool dco = false) ClientOptions cliopt(options, config); } -TEST(config, missingRequiredOption) +TEST_P(ValidConfigs, valid_config) { - ParseClientConfig conf = ParseClientConfig::parse("mode server"); - EXPECT_EQ(conf.error(), true); - EXPECT_TRUE(conf.message().find("option_error: remote option not specified") != std::string::npos); + load_client_config(GetParam()); } -TEST(config, parse_missing_option) +TEST_P(InvalidConfigs, config_throws_option_error) { OVPN_EXPECT_THROW( - load_client_config(std::string("remote wooden.box\n") + "mode server" - + "\n\n" + dummysecp256cert + "\n"), + load_client_config(GetParam().first), option_error, - "option 'cert' not found"); + GetParam().second); } -TEST(config, parse_forbidden_option) +TEST(config, missingRequiredOption) { - OVPN_EXPECT_THROW( - load_client_config(minimalConfig + "mode"), - option_error, - "Only 'mode p2p' supported"); - - OVPN_EXPECT_THROW( - load_client_config(minimalConfig + "mode server"), - option_error, - "Only 'mode p2p' supported"); - - OVPN_EXPECT_THROW( - load_client_config(minimalConfig + "key-method 1"), - option_error, - "Only 'key-method 2' is supported"); - - OVPN_EXPECT_THROW( - load_client_config(minimalConfig + "fragment"), - option_error, - "sorry, 'fragment' directive is not supported"); + ParseClientConfig conf = ParseClientConfig::parse("mode server"); + EXPECT_EQ(conf.error(), true); + EXPECT_EQ(conf.message(), "ERR_INVALID_CONFIG: option_error: remote option not specified"); } +INSTANTIATE_TEST_SUITE_P( + optionError, + InvalidConfigs, + testing::Values( + config_error{std::string("remote wooden.box\n") + "mode server" + + "\n\n" + dummysecp256cert + "\n", + "option 'cert' not found"}, + config_error{minimalConfig + "mode", "Only 'mode p2p' supported"}, + config_error{minimalConfig + "mode server", "Only 'mode p2p' supported"}, + config_error{minimalConfig + "key-method 1", "Only 'key-method 2' is supported"}, + config_error{minimalConfig + "fragment", "sorry, 'fragment' directive is not supported"})); + TEST(config, parse_unknown_option) { OVPN_EXPECT_THROW( @@ -100,27 +101,20 @@ TEST(config, parse_unknown_option) "UNKNOWN/UNSUPPORTED OPTIONS"); } -TEST(config, duplicate_option) -{ - /* A duplicate option should not cause our parser to fail */ - load_client_config(minimalConfig + "cipher AES-192-CBC\ncipher AES-256-GCM\n"); -} - -TEST(config, parse_ignore_unkown) -{ - /* Bikeshed colour is ignored should throw no error */ - load_client_config(minimalConfig + "ignore-unknown-option bikeshed-colour bikeshed-color\n" - "ignore-unknown-option danish axe phk\n" - "bikeshed-colour green"); - - load_client_config(minimalConfig + "setenv opt bikeshed-paint silver with sparkling"); -} - -TEST(config, ignore_warning_option) -{ - load_client_config(minimalConfig + "tun-ipv6\n"); - load_client_config(minimalConfig + "opt-verify\n"); -} +INSTANTIATE_TEST_SUITE_P( + minimalConfigs, + ValidConfigs, + testing::Values( + /* A duplicate option should not cause our parser to fail */ + minimalConfig + "cipher AES-192-CBC\ncipher AES-256-GCM\n", + /* Bikeshed colour is ignored should throw no error */ + minimalConfig + "ignore-unknown-option bikeshed-colour bikeshed-color\n" + "ignore-unknown-option danish axe phk\n" + "bikeshed-colour green", + minimalConfig + "setenv opt bikeshed-paint silver with sparkling", + /* warnings, but no errors */ + minimalConfig + "tun-ipv6\n", + minimalConfig + "opt-verify\n")); TEST(config, parse_management) { @@ -180,20 +174,13 @@ TEST(config, dco_compatibility) { for (auto optname : ClientOptions::dco_incompatible_opts) { - ClientAPI::Config api_config; - - /* If we just use http-proxy without argument, we will bail out for - * missing parameter instead */ if (optname == "http-proxy") - optname = "proto tcp\nhttp-proxy 1.1.1.1 8080"; - - api_config.dco = true; - api_config.content = minimalConfig + optname; - ClientAPI::OpenVPNClientHelper client_helper; - auto eval = client_helper.eval_config(api_config); - - EXPECT_FALSE(eval.dcoCompatible); - + { + // The option parser is picky; it's needed to + // provide all the proper arguments to 'http-proxy' + // and tcp is required for the protocol + optname += " 10.0.0.1 8080\nproto tcp\n"; + } OVPN_EXPECT_THROW( load_client_config(minimalConfig + optname), option_error, @@ -247,42 +234,27 @@ TEST(config, multiple_option_errors) os.str()); } -TEST(config, client_missing_in_config) -{ - std::string configNoClient = certconfig + "\nremote 1.2.3.4\n"; - OVPN_EXPECT_THROW( - load_client_config(configNoClient), - option_error, - "ERR_INVALID_CONFIG: option_error: Neither 'client' nor both 'tls-client' and 'pull' options declared. OpenVPN3 client only supports --client mode."); -} - -TEST(config, pull_and_tlsclient_in_config) -{ - std::string configNoClient = certconfig + "\nremote 1.2.3.4\ntls-client\npull\n"; - /* Should not trigger an error, even without --client in place */ - load_client_config(configNoClient); -} - -TEST(config, pull_and_client_and_tlsclient_in_config) -{ - std::string configNoClient = certconfig + "\nremote 1.2.3.4\ntls-client\npull\nclient\n"; - /* Should not trigger an error. Redundant options are no problem */ - load_client_config(configNoClient); -} - -TEST(config, onlypullortlsclient) -{ - std::array options{"tls-client", "pull"}; - - for (const auto &opt : options) - { - std::string configNoClient = certconfig + "\nremote 1.2.3.4\n" + opt + "\n"; - OVPN_EXPECT_THROW( - load_client_config(configNoClient), - option_error, - "ERR_INVALID_CONFIG: option_error: Neither 'client' nor both 'tls-client' and 'pull' options declared. OpenVPN3 client only supports --client mode."); - } -} +INSTANTIATE_TEST_SUITE_P( + clientPull, + ValidConfigs, + testing::Values( + /* Should not trigger an error, even without --client in place */ + certconfig + "\nremote 1.2.3.4\ntls-client\npull\n", + /* Should not trigger an error. Redundant options are no problem */ + certconfig + "\nremote 1.2.3.4\ntls-client\npull\nclient\n", + certconfig + "\nremote 1.2.3.4\npull\nclient\n", + certconfig + "\nremote 1.2.3.4\nclient\ntls-client\n")); + +INSTANTIATE_TEST_SUITE_P( + clientPull, + InvalidConfigs, + testing::Values( + config_error{certconfig + "\nremote 1.2.3.4\n", + "option_error: Neither 'client' nor both 'tls-client' and 'pull' options declared. OpenVPN3 client only supports --client mode."}, + config_error{certconfig + "\nremote 1.2.3.4\ntls-client\n", + "option_error: Neither 'client' nor both 'tls-client' and 'pull' options declared. OpenVPN3 client only supports --client mode."}, + config_error{certconfig + "\nremote 1.2.3.4\npull\n", + "option_error: Neither 'client' nor both 'tls-client' and 'pull' options declared. OpenVPN3 client only supports --client mode."})); TEST(config, meta_option_in_content) { diff --git a/test/unittests/test_ip.cpp b/test/unittests/test_ip.cpp index c98ec74df..55d533fde 100644 --- a/test/unittests/test_ip.cpp +++ b/test/unittests/test_ip.cpp @@ -9,6 +9,10 @@ #include #include +#if defined(SIN6_LEN) || defined(__APPLE__) || defined(__FreeBSD__) +#include +#endif + using namespace openvpn; static const uint8_t icmp6_packet[] = { @@ -134,6 +138,11 @@ void do_shift_tests(const std::vector &test_vectors, bool leftshift) auto ret = shifted_addr.to_sockaddr(); sockaddr_in6 cmp{}; +#if defined(SIN6_LEN) || defined(__APPLE__) || defined(__FreeBSD__) + /* Enable this test on the platforms that we know to have sin6_len + * to not only depend on SIN6_LEN */ + cmp.sin6_len = sizeof(sockaddr_in6); +#endif cmp.sin6_family = AF_INET6; for (int i = 0; i < 16; i++) {