├── .gitignore ├── CHANGELOG ├── CMakeLists.txt ├── LICENSE ├── README.md ├── Stubby.icns ├── cmake └── modules │ └── FindLibctemplate.cmake ├── config.cpp ├── config.h ├── configmanager.cpp ├── configmanager.h ├── images ├── getdns_logo.png ├── off.png ├── on.png ├── stubby.ico ├── stubby@245x145.png ├── stubby@245x145_green.png └── stubby@245x145_red.png ├── logmanager.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── netprofile_defaults.yml ├── networkinterface.hpp ├── networkmanager.cpp ├── networkmanager.h ├── networkprofiledelegate.cpp ├── networkprofiledelegate.h ├── networkprofiletablemodel.cpp ├── networkprofiletablemodel.h ├── networkprofilewidget.cpp ├── networkprofilewidget.h ├── networkprofilewidget.ui ├── networkswidget.cpp ├── networkswidget.h ├── networkswidget.ui ├── networkswidgetfilterproxymodel.cpp ├── networkswidgetfilterproxymodel.h ├── os ├── linux │ ├── configmanager_linux.cpp │ ├── configmanager_linux.h │ ├── logmanager_linux.cpp │ ├── logmanager_linux.h │ ├── networkmanager_linux.cpp │ ├── networkmanager_linux.h │ ├── servicemanager_linux.cpp │ └── servicemanager_linux.h ├── macos │ ├── configmanager_macos.cpp │ ├── configmanager_macos.h │ ├── logmanager_macos.cpp │ ├── logmanager_macos.h │ ├── networkmanager_macos.cpp │ ├── networkmanager_macos.h │ ├── runtask_macos.cpp │ ├── runtask_macos.h │ ├── servicemanager_macos.cpp │ └── servicemanager_macos.h └── windows │ ├── StubbyManager.xml │ ├── StubbySetDns.ps1 │ ├── configmanager_windows.cpp │ ├── configmanager_windows.h │ ├── exceptions_windows.h │ ├── logmanager_windows.cpp │ ├── logmanager_windows.h │ ├── networkinterface_windows.cpp │ ├── networkinterface_windows.hpp │ ├── networkmanager_windows.cpp │ ├── networkmanager_windows.h │ ├── servicemanager_windows.cpp │ ├── servicemanager_windows.h │ ├── stubbygui.ico │ ├── stubbygui.rc.in │ ├── stubbygui.wxs │ └── windows_package_version.in ├── serverdatadialog.cpp ├── serverdatadialog.h ├── serverdatadialog.ui ├── serverstablemodel.cpp ├── serverstablemodel.h ├── servicemanager.cpp ├── servicemanager.h ├── stubby.qrc ├── stubbytemplate.yml └── utils ├── env-debug.bat └── env-release.bat /.gitignore: -------------------------------------------------------------------------------- 1 | *.autosave 2 | *.user* 3 | build* 4 | build_qmake* 5 | build-stubby* 6 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Version 0.4.4-rc1 - 2023-07-26 2 | 3 | * Fix regex for package generation 4 | * Remove Sinodun servers from config 5 | * Version aligned with Stubby 6 | 7 | 8 | Version 0.4.0-alpha2 - 2020-12-12 9 | 10 | * Split the networks into wireless and wired and display active networks 11 | as green. 12 | * Re-factor internals so saved profile is the base reference 13 | * Move default profile selection from Network Profile to Networks tab 14 | * Add default option to profile and require one to be set for now 15 | * Automatically save a new config and restart the service if the current 16 | profile would change because the active network interfaces change 17 | * Enable editing of server properties 18 | * Review of log messages and serveral error paths 19 | * Fix crash on load of invalid configuration file 20 | * Add serveral alerts to the system tray 21 | * Update the Trusted profile default servers to be Quad9 22 | * Convert 3rd column of server table to be clickable link 23 | * Re-factor cascade of network changes through code 24 | * Detect whether network properties we really care about have actually 25 | changed on a callback from the system network manager 26 | * Add validation on save of network profile settings and also on 27 | export of stubby service file 28 | * Add button to forget wireless networks 29 | * Add StubbyManager.xml file so user can configure service to 30 | automatically start at login/restart 31 | * Improve handling of unsaved changes and ensure quitting from the 32 | system tray icon also prompts for this 33 | * Add first run dialog to inform user Stubby runs as a system tray 34 | process 35 | * Add process report to installer 36 | 37 | 38 | Version 0.4.0-alpha1 - 2020-09-25 39 | 40 | * First alpha version of GUI for Windows. -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | if (POLICY CMP0075) 4 | cmake_policy(SET CMP0075 NEW) 5 | endif () 6 | 7 | # The following must be set BEFORE doing project() or enable_language(). 8 | if (NOT CMAKE_BUILD_TYPE) 9 | message(STATUS "No build type defined; defaulting to 'Debug'") 10 | set(CMAKE_BUILD_TYPE "Debug" CACHE STRING 11 | "The type of build. Possible values are: Debug, Release, RelWithDebInfo and MinSizeRel.") 12 | endif () 13 | 14 | set(PACKAGE_NAME "Stubby Manager") 15 | set(PACKAGE_VERSION_MAJOR 0) 16 | set(PACKAGE_VERSION_MINOR 4) 17 | set(PACKAGE_VERSION_RELEASE 4) 18 | set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_RELEASE}") 19 | set(PACKAGE_BUGREPORT "info@sinodun.com") 20 | set(RELEASE_CANDIDATE "rc1") 21 | 22 | set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}${RELEASE_CANDIDATE}") 23 | set(PACKAGE_TARNAME "${PACKAGE}-${PACKAGE_VERSION}${RELEASE_CANDIDATE}") 24 | 25 | if (WIN32) 26 | project (stubby_gui VERSION ${PACKAGE_VERSION} LANGUAGES CXX RC) 27 | else() 28 | project (stubby_gui VERSION ${PACKAGE_VERSION} LANGUAGES CXX) 29 | endif() 30 | 31 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") 32 | 33 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 34 | 35 | set(CMAKE_AUTOUIC ON) 36 | set(CMAKE_AUTOMOC ON) 37 | set(CMAKE_AUTORCC ON) 38 | 39 | set(CMAKE_CXX_STANDARD 14) 40 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 41 | 42 | 43 | if (WIN32 OR MINGW OR MSYS OR CYGWIN) 44 | set(HOSTOS "windows") 45 | elseif (APPLE) 46 | set(HOSTOS "macos") 47 | elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 48 | set(HOSTOS "linux") 49 | else () 50 | message(FATAL_ERROR "Support limited to Windows, MacOS and Linux.") 51 | endif () 52 | set(os_src_dir "os/${HOSTOS}") 53 | 54 | # Windows. 55 | if (WIN32) 56 | option(PATCH_LEVEL_GIT "Get patch level from git." OFF) 57 | 58 | set(system_libs "") 59 | set(static_lib_suffix "_static") 60 | list(APPEND system_libs 61 | "ws2_32" 62 | "crypt32" 63 | "gdi32" 64 | "iphlpapi" 65 | "psapi" 66 | "userenv" 67 | "wlanapi" 68 | ) 69 | endif() 70 | 71 | find_package(Qt5 COMPONENTS Widgets REQUIRED) 72 | find_package(yaml-cpp REQUIRED) 73 | find_package(Libctemplate REQUIRED) 74 | if (WIN32) 75 | find_package(Poco COMPONENTS Net REQUIRED) 76 | find_package(Qt5 COMPONENTS Network REQUIRED) 77 | 78 | set(PACKAGE_VERSION_PATCH 0) 79 | if (PATCH_LEVEL_GIT) 80 | execute_process(COMMAND git describe --long OUTPUT_VARIABLE ver) 81 | if (ver) 82 | string(REGEX REPLACE "v[^-]*-[a-z]*([0-9]*)-.*" "\\1" PACKAGE_VERSION_PATCH ${ver}) 83 | endif () 84 | endif () 85 | 86 | set(VER_PRODUCTVERSION "${PACKAGE_VERSION_MAJOR},${PACKAGE_VERSION_MINOR},${PACKAGE_VERSION_RELEASE},${PACKAGE_VERSION_PATCH}") 87 | set(VER_PRODUCTVERSION_STR "${PACKAGE_VERSION}${RELEASE_CANDIDATE}") 88 | configure_file(${os_src_dir}/stubbygui.rc.in stubbygui.rc @ONLY) 89 | configure_file(${os_src_dir}/stubbygui.ico stubbygui.ico COPYONLY) 90 | set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/stubby.qrc") 91 | set(WINDOWS_PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_RELEASE}.${PACKAGE_VERSION_PATCH}") 92 | configure_file(${os_src_dir}/windows_package_version.in windows_package_version @ONLY) 93 | elseif (APPLE) 94 | find_package(Qt5 COMPONENTS Macextras REQUIRED) 95 | endif() 96 | 97 | if (WIN32) 98 | set(PLAFORM_BUILD WIN32) 99 | elseif (APPLE) 100 | set(PLAFORM_BUILD MACOSX_BUNDLE) 101 | else() 102 | set(PLAFORM_BUILD "") 103 | endif() 104 | add_executable( stubby_gui ${PLAFORM_BUILD} 105 | main.cpp 106 | mainwindow.cpp 107 | mainwindow.ui 108 | networkprofilewidget.cpp 109 | networkprofilewidget.ui 110 | networkprofiledelegate.cpp 111 | networkswidget.cpp 112 | networkswidgetfilterproxymodel.cpp 113 | networkswidget.ui 114 | config.cpp 115 | configmanager.cpp 116 | networkprofiletablemodel.cpp 117 | serverstablemodel.cpp 118 | serverdatadialog.cpp 119 | serverdatadialog.ui 120 | servicemanager.cpp 121 | networkmanager.cpp 122 | stubby.qrc 123 | ${os_src_dir}/configmanager_${HOSTOS}.cpp 124 | ${os_src_dir}/servicemanager_${HOSTOS}.cpp 125 | ${os_src_dir}/networkmanager_${HOSTOS}.cpp 126 | ${os_src_dir}/logmanager_${HOSTOS}.cpp 127 | ${APP_ICON_RESOURCE_WINDOWS} 128 | ) 129 | 130 | if(WIN32) 131 | target_sources(stubby_gui PRIVATE ${os_src_dir}/networkinterface_${HOSTOS}.cpp) 132 | SET(WINDOWS_RESOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/stubbygui.rc) 133 | target_sources(stubby_gui PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/stubbygui.rc) 134 | 135 | target_link_options(stubby_gui PRIVATE "/MANIFESTUAC:level='requireAdministrator'") 136 | elseif(APPLE) 137 | target_sources(stubby_gui PRIVATE ${os_src_dir}/runtask_${HOSTOS}.cpp) 138 | endif() 139 | 140 | target_include_directories(stubby_gui 141 | PUBLIC 142 | . 143 | ${LIBCTEMPLATE_INCLUDE_DIR} 144 | ${YAML_CPP_INCLUDE_DIR} 145 | ${os_src_dir} 146 | ${CMAKE_CURRENT_BINARY_DIR} 147 | ) 148 | 149 | if(WIN32) 150 | target_link_libraries(stubby_gui PUBLIC 151 | ${system_libs} 152 | PRIVATE 153 | Qt5::Network 154 | Qt5::Widgets 155 | Poco::Net 156 | Libctemplate::Libctemplate 157 | ${YAML_CPP_LIBRARIES}) 158 | elseif(APPLE) 159 | target_link_libraries(stubby_gui PRIVATE 160 | "-framework Foundation" 161 | "-framework AppKit" 162 | "-framework Security" 163 | Qt5::Widgets 164 | Qt5::MacExtras 165 | Libctemplate::Libctemplate 166 | ${YAML_CPP_LIBRARIES}) 167 | else() 168 | target_link_libraries(stubby_gui PRIVATE 169 | Qt5::Widgets 170 | Libctemplate::Libctemplate 171 | ${YAML_CPP_LIBRARIES}) 172 | endif() 173 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE/* 2 | * Copyright 2017 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stubby Manager 2 | 3 | A GUI to control [Stubby](https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Daemon+-+Stubby) (a DNS Privacy stub resolver). 4 | 5 | Developed by [ [Sinodun IT](https://sinodun.com) for dnsprivacy.org](https://dnsprivacy.org). 6 | 7 | ## Current release 8 | 9 | The current release is an **alpha development release** for early testing. It is not feature complete and should be used with care! 10 | 11 | ## Installation 12 | 13 | The GUI is currently only supported on Windows, macOS support is a work in progress 14 | 15 | ### Windows installer 16 | 17 | See [Stubby Manager](https://dnsprivacy.org/wiki/display/DP/Stubby+Manager+GUI) on dnsprivacy.org 18 | 19 | ## Documentation 20 | 21 | See [Stubby Manager](https://dnsprivacy.org/wiki/display/DP/Stubby+Manager+GUI) 22 | 23 | ## Building from source 24 | 25 | The code is available from https://github.com/Sinodun/Stubby_Manager. 26 | 27 | It is built with Qt 5.15 and requires the following libraries: 28 | 29 | * libctemplate 30 | * poco 31 | * yaml-cpp 32 | 33 | ## Acknowledgements 34 | 35 | dnsprivacy.org thanks the [Comcast Innovation Fund](https://innovationfund.comcast.com) for significant funding towards this project. 36 | 37 | ## Contributors 38 | 39 | * Sara Dickinson 40 | * John Dickinson 41 | * Jim Hague 42 | * Georgina Hawes 43 | * Molly Carton 44 | -------------------------------------------------------------------------------- /Stubby.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/Stubby.icns -------------------------------------------------------------------------------- /cmake/modules/FindLibctemplate.cmake: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | FindLibctemplate 3 | ---------------- 4 | 5 | Find the Libctemplate library. 6 | 7 | Imported targets 8 | ^^^^^^^^^^^^^^^^ 9 | 10 | This module defines the following :prop_tgt:`IMPORTED` targets: 11 | 12 | ``Libctemplate::Libctemplate`` 13 | The Libctemplate library, if found. 14 | 15 | Result variables 16 | ^^^^^^^^^^^^^^^^ 17 | 18 | This module will set the following variables in your project: 19 | 20 | ``Libctemplate_FOUND`` 21 | If false, do not try to use Libctemplate. 22 | ``LIBCTEMPLATE_INCLUDE_DIR`` 23 | where to find libctemplate headers. 24 | ``LIBCTEMPLATE_LIBRARIES`` 25 | the libraries needed to use Libctemplate. 26 | ``LIBCTEMPLATE_VERSION`` 27 | the version of the Libctemplate library found 28 | 29 | #]=======================================================================] 30 | 31 | find_path(LIBCTEMPLATE_INCLUDE_DIR ctemplate/template.h 32 | HINTS 33 | "${LIBCTEMPLATE_DIR}" 34 | "${LIBCTEMPLATE_DIR}/include" 35 | ) 36 | 37 | find_library(LIBCTEMPLATE_LIBRARY NAMES ctemplate libctemplate 38 | HINTS 39 | "${LIBCTEMPLATE_DIR}" 40 | "${LIBCTEMPLATE_DIR}/lib" 41 | ) 42 | 43 | set(LIBCTEMPLATE_LIBRARIES "") 44 | 45 | if (LIBCTEMPLATE_INCLUDE_DIR AND LIBCTEMPLATE_LIBRARY) 46 | if (NOT TARGET Libctemplate::Libctemplate) 47 | add_library(Libctemplate::Libctemplate UNKNOWN IMPORTED) 48 | set_target_properties(Libctemplate::Libctemplate PROPERTIES 49 | INTERFACE_INCLUDE_DIRECTORIES "${LIBCTEMPLATE_INCLUDE_DIR}" 50 | IMPORTED_LINK_INTERFACE_LANGUAGES "C++" 51 | IMPORTED_LOCATION "${LIBCTEMPLATE_LIBRARY}" 52 | ) 53 | endif () 54 | endif() 55 | 56 | list(APPEND LIBCTEMPLATE_LIBRARIES "${LIBCTEMPLATE_LIBRARY}") 57 | 58 | include(FindPackageHandleStandardArgs) 59 | find_package_handle_standard_args(Libctemplate 60 | REQUIRED_VARS LIBCTEMPLATE_LIBRARIES LIBCTEMPLATE_INCLUDE_DIR 61 | ) 62 | 63 | mark_as_advanced(LIBCTEMPLATE_INCLUDE_DIR LIBCTEMPLATE_LIBRARIES LIBCTEMPLATE_LIBRARY) 64 | -------------------------------------------------------------------------------- /config.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef _MSC_VER 15 | #pragma warning(push) 16 | #pragma warning(disable: 4251 4275) 17 | #endif 18 | 19 | #include 20 | 21 | #ifdef _MSC_VER 22 | #pragma warning(pop) 23 | #endif 24 | 25 | #include "config.h" 26 | 27 | Config::Server::Server(const std::string& name, const std::string& link, const std::vector& addrs, const std::string& authName, const std::string& digest) 28 | : name(name), link(link), addresses(addrs), tlsAuthName(authName), 29 | pubKeyDigestType("sha256"), pubKeyDigestValue(digest), 30 | hidden(), inactive() 31 | { 32 | } 33 | 34 | Config::Server::Server() 35 | : name(), link(), addresses(), tlsAuthName(), 36 | pubKeyDigestType("sha256"), pubKeyDigestValue(), 37 | hidden(), inactive() 38 | { 39 | } 40 | 41 | Config::Profile::Profile (bool encryptAll, bool alwaysAuthenticate, 42 | bool validateData, bool roundRobin, 43 | UseNetworkProvidedServer useNetworkProvidedServer) 44 | : encryptAll(encryptAll), alwaysAuthenticate(alwaysAuthenticate), 45 | validateData(validateData), roundRobin(roundRobin), 46 | useNetworkProvidedServer(useNetworkProvidedServer) 47 | { 48 | } 49 | 50 | Config::Profile::Profile() 51 | : encryptAll(), alwaysAuthenticate(), 52 | validateData(), roundRobin(), 53 | useNetworkProvidedServer() 54 | { 55 | } 56 | 57 | Config::Config() 58 | : servers(), profiles(), 59 | defaultNetworkProfile(NetworkProfile::untrusted), networks() 60 | { 61 | reset(); 62 | } 63 | 64 | void Config::reset() 65 | { 66 | servers.clear(); 67 | servers.push_back(Server("Stubby server (getdnsapi.net)", "dnsprivacy.org", {"185.49.141.37"}, "getdnsapi.net", "foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=")); 68 | 69 | profiles.clear(); 70 | profiles[NetworkProfile::trusted] = Profile({ false, false, false, false, UseNetworkProvidedServer::use_only }); 71 | profiles[NetworkProfile::untrusted] = Profile({ true, true, false, false, UseNetworkProvidedServer::include }); 72 | profiles[NetworkProfile::hostile] = Profile({ true, true, false, false, UseNetworkProvidedServer::exclude }); 73 | 74 | defaultNetworkProfile = NetworkProfile::untrusted; 75 | } 76 | 77 | static Config::NetworkProfile networkProfileFromYaml(const std::string& key, const YAML::Mark& mark) 78 | { 79 | try 80 | { 81 | return Config::networkProfileFromYamlKey(key); 82 | } 83 | catch (const std::invalid_argument& ie) 84 | { 85 | throw YAML::ParserException(mark, ie.what()); 86 | } 87 | } 88 | 89 | static Config::NetworkProfileChoice networkProfileChoiceFromYaml(const std::string& key, const YAML::Mark& mark) 90 | { 91 | try 92 | { 93 | return Config::networkProfileChoiceFromYamlKey(key); 94 | } 95 | catch (const std::invalid_argument& ie) 96 | { 97 | throw YAML::ParserException(mark, ie.what()); 98 | } 99 | } 100 | 101 | static void yamlInputNetworkProfileSet(const YAML::Node& yml, const std::string& name, std::unordered_set& set) 102 | { 103 | if ( !yml || yml.Type() != YAML::NodeType::Sequence ) 104 | throw YAML::ParserException(yml.Mark(), "server must have " + name + " sequence"); 105 | 106 | for ( const auto& nt : yml ) 107 | set.insert(networkProfileFromYaml(nt.as(), yml.Mark())); 108 | } 109 | 110 | void Config::loadFromFile(const std::string& path) 111 | { 112 | YAML::Node ymlcfg = YAML::LoadFile(path); 113 | 114 | servers.clear(); 115 | profiles.clear(); 116 | networks.clear(); 117 | 118 | YAML::Node ymlservers = ymlcfg["servers"]; 119 | if ( !ymlservers ) 120 | throw YAML::ParserException(ymlcfg.Mark(), "Missing 'servers' list"); 121 | if ( ymlservers.Type() != YAML::NodeType::Sequence ) 122 | throw YAML::ParserException(ymlcfg.Mark(), "'servers' must be a sequence"); 123 | for ( const auto& s : ymlservers ) 124 | { 125 | if ( s.Type() != YAML::NodeType::Map ) 126 | throw YAML::ParserException(ymlservers.Mark(), "'servers' entry must be a map"); 127 | Server server; 128 | server.name = s["name"].as(); 129 | server.link = s["link"].as(); 130 | server.tlsAuthName = s["tls_auth_name"].as(); 131 | 132 | YAML::Node ymladdrs = s["addresses"]; 133 | if ( !ymladdrs || !ymladdrs.size() ) 134 | throw YAML::ParserException(ymladdrs.Mark(), "server must have at least 1 address"); 135 | for ( const auto& a : ymladdrs ) 136 | server.addresses.push_back(a.as()); 137 | 138 | YAML::Node ymlpinset = s["tls_pubkey_pinset"]; 139 | if ( !ymlpinset || ymlpinset.Type() != YAML::NodeType::Map ) 140 | throw YAML::ParserException(ymladdrs.Mark(), "server must have tls_pubkey_pinset map"); 141 | server.pubKeyDigestType = ymlpinset["digest"].as(); 142 | server.pubKeyDigestValue = ymlpinset["value"].as(); 143 | 144 | yamlInputNetworkProfileSet(s["hidden"], "hidden", server.hidden); 145 | yamlInputNetworkProfileSet(s["inactive"], "inactive", server.inactive); 146 | 147 | servers.push_back(server); 148 | } 149 | 150 | YAML::Node ymlprofiles = ymlcfg["profiles"]; 151 | if ( !ymlprofiles ) 152 | throw YAML::ParserException(ymlcfg.Mark(), "Missing 'profiles' map"); 153 | if ( ymlprofiles.Type() != YAML::NodeType::Map ) 154 | throw YAML::ParserException(ymlcfg.Mark(), "'profiles' must be a map"); 155 | for ( const auto& n : ymlprofiles ) 156 | { 157 | NetworkProfile nt = networkProfileFromYaml(n.first.as(), ymlcfg.Mark()); 158 | Profile prof; 159 | prof.encryptAll = n.second["encrypt_all"].as(); 160 | prof.alwaysAuthenticate = n.second["always_authenticate"].as(); 161 | prof.validateData = n.second["validate_data"].as(); 162 | prof.roundRobin = n.second["round_robin"].as(); 163 | 164 | std::string unps = n.second["user_network_provided_servers"].as(); 165 | if ( unps == "exclude" ) 166 | prof.useNetworkProvidedServer = UseNetworkProvidedServer::exclude; 167 | else if ( unps == "include" ) 168 | prof.useNetworkProvidedServer = UseNetworkProvidedServer::include; 169 | else if ( unps == "use-only" ) 170 | prof.useNetworkProvidedServer = UseNetworkProvidedServer::use_only; 171 | else 172 | throw YAML::ParserException(n.Mark(), "bad value " + unps); 173 | 174 | profiles[nt] = prof; 175 | } 176 | 177 | YAML::Node ymldefnetprofile = ymlcfg["default_network_profile"]; 178 | if ( ymldefnetprofile ) 179 | defaultNetworkProfile = networkProfileFromYaml(ymldefnetprofile.as(), ymlcfg.Mark()); 180 | 181 | YAML::Node ymlnetworks = ymlcfg["networks"]; 182 | if ( !ymlnetworks ) 183 | throw YAML::ParserException(ymlcfg.Mark(), "Missing 'networks' map"); 184 | if ( ymlnetworks.Type() != YAML::NodeType::Map ) 185 | throw YAML::ParserException(ymlcfg.Mark(), "'networks' must be a map"); 186 | for ( const auto& n : ymlnetworks ) 187 | { 188 | std::string name = n.first.as(); 189 | NetworkProfileChoice profile = networkProfileChoiceFromYaml(n.second["profile"].as(), ymlnetworks.Mark()); 190 | networks[name].profile = profile; 191 | std::string type = n.second["type"].as(); 192 | networks[name].interfaceType = (InterfaceTypes)std::atoi(type.c_str()); 193 | } 194 | } 195 | 196 | static void yamlOutputNetworkProfileSet(YAML::Emitter& out, const std::unordered_set& set) 197 | { 198 | out << YAML::BeginSeq; 199 | for ( const auto& np : set ) 200 | out << Config::networkProfileYamlKey(np); 201 | out << YAML::EndSeq; 202 | } 203 | 204 | void Config::saveToFile(const std::string& path) const 205 | { 206 | std::ofstream fout(path); 207 | fout.exceptions(std::ofstream::failbit | std::ofstream::badbit); 208 | 209 | YAML::Emitter out(fout); 210 | 211 | out << YAML::BeginMap << YAML::Key << "servers" << YAML::BeginSeq; 212 | for ( const auto& s : servers ) 213 | { 214 | out << YAML::BeginMap; 215 | out << YAML::Key << "name" << YAML::Value << s.name; 216 | out << YAML::Key << "link" << YAML::Value << s.link; 217 | out << YAML::Key << "addresses" << YAML::Value << s.addresses; 218 | out << YAML::Key << "tls_auth_name" << YAML::Value << s.tlsAuthName; 219 | out << YAML::Key << "tls_pubkey_pinset" << YAML::Value 220 | << YAML::BeginMap 221 | << YAML::Key << "digest" << YAML::Value << s.pubKeyDigestType 222 | << YAML::Key << "value" << YAML::Value << s.pubKeyDigestValue 223 | << YAML::EndMap; 224 | out << YAML::Key << "hidden"; 225 | yamlOutputNetworkProfileSet(out, s.hidden); 226 | out << YAML::Key << "inactive"; 227 | yamlOutputNetworkProfileSet(out, s.inactive); 228 | out << YAML::EndMap; 229 | } 230 | out << YAML::EndSeq; 231 | 232 | out << YAML::Key << "profiles" << YAML::Value << YAML::BeginMap; 233 | for (const auto& nt : profiles) 234 | { 235 | out << YAML::Key << networkProfileYamlKey(nt.first) << YAML::Value 236 | << YAML::BeginMap 237 | << YAML::Key << "encrypt_all" << YAML::Value << nt.second.encryptAll 238 | << YAML::Key << "always_authenticate" << YAML::Value << nt.second.alwaysAuthenticate 239 | << YAML::Key << "validate_data" << YAML::Value << nt.second.validateData 240 | << YAML::Key << "round_robin" << YAML::Value << nt.second.roundRobin 241 | << YAML::Key << "user_network_provided_servers" << YAML::Value; 242 | switch(nt.second.useNetworkProvidedServer) 243 | { 244 | case UseNetworkProvidedServer::exclude: 245 | out << "exclude"; 246 | break; 247 | 248 | case UseNetworkProvidedServer::include: 249 | out << "include"; 250 | break; 251 | 252 | case UseNetworkProvidedServer::use_only: 253 | out << "use-only"; 254 | break; 255 | } 256 | out << YAML::EndMap; 257 | } 258 | out << YAML::EndMap; 259 | 260 | out << YAML::Key << "default_network_profile" << YAML::Value << networkProfileYamlKey(defaultNetworkProfile); 261 | 262 | out << YAML::Key << "networks" << YAML::Value << YAML::BeginMap; 263 | for (const auto& nt : networks) { 264 | out << YAML::Key << nt.first << YAML::Value; 265 | out << YAML::BeginMap; 266 | out << YAML::Key << "profile" << YAML::Value << networkProfileChoiceYamlKey(nt.second.profile); 267 | out << YAML::Key << "type" << YAML::Value << nt.second.interfaceType; 268 | out << YAML::EndMap; 269 | } 270 | out << YAML::EndMap; 271 | 272 | fout.close(); 273 | } 274 | 275 | bool Config::Server::operator==(const Config::Server& server) const 276 | { 277 | return 278 | name == server.name && 279 | link == server.link && 280 | addresses == server.addresses && 281 | tlsAuthName == server.tlsAuthName && 282 | pubKeyDigestType == server.pubKeyDigestType && 283 | pubKeyDigestValue == server.pubKeyDigestValue && 284 | hidden == server.hidden && 285 | inactive == server.inactive; 286 | } 287 | 288 | bool Config::serverDataIsEqual(const Config::Server& server1, const Config::Server& server2) const 289 | { 290 | return 291 | server1.name == server2.name && 292 | server1.link == server2.link && 293 | server1.addresses == server2.addresses && 294 | server1.tlsAuthName == server2.tlsAuthName && 295 | server1.pubKeyDigestType == server2.pubKeyDigestType && 296 | server1.pubKeyDigestValue == server2.pubKeyDigestValue; 297 | } 298 | 299 | bool Config::serverActiveIsEqualForProfile(const Config::Server& server1, const Config::Server& server2, Config::NetworkProfile profile) const 300 | { 301 | if (server1.inactive.find(profile) != server1.inactive.end() && 302 | server2.inactive.find(profile) != server2.inactive.end()) 303 | return true; 304 | if (server1.inactive.find(profile) == server1.inactive.end() && 305 | server2.inactive.find(profile) == server2.inactive.end()) 306 | return true; 307 | return false; 308 | } 309 | 310 | void Config::Server::setServerDataEqual(const Config::Server& server) 311 | { 312 | name = server.name; 313 | link = server.link; 314 | addresses = server.addresses; 315 | tlsAuthName = server.tlsAuthName; 316 | pubKeyDigestType = server.pubKeyDigestType; 317 | pubKeyDigestValue = server.pubKeyDigestValue; 318 | } 319 | 320 | void Config::Server::setServerActiveEqualForProfile(const Config::Server& server, Config::NetworkProfile profile) 321 | { 322 | if (server.inactive.find(profile) != server.inactive.end()) { 323 | // profile is in inactive list 324 | if (inactive.find(profile) == inactive.end()) { 325 | inactive.insert(profile); 326 | } 327 | } else if (server.inactive.find(profile) == server.inactive.end()) { 328 | // profile is NOT in inactive list 329 | if (inactive.find(profile) != inactive.end()) { 330 | inactive.erase(profile); 331 | } 332 | } 333 | } 334 | 335 | bool Config::Profile::operator==(const Config::Profile& server) const 336 | { 337 | return 338 | encryptAll == server.encryptAll && 339 | alwaysAuthenticate == server.alwaysAuthenticate && 340 | validateData == server.validateData && 341 | roundRobin == server.roundRobin && 342 | useNetworkProvidedServer == server.useNetworkProvidedServer; 343 | } 344 | 345 | bool Config::NetworkInformation::operator==(const Config::NetworkInformation& netinfo) const 346 | { 347 | return 348 | profile == netinfo.profile && 349 | interfaceType == netinfo.interfaceType && 350 | interfaceActive == netinfo.interfaceActive; 351 | } 352 | 353 | bool Config::operator==(const Config& cfg) const 354 | { 355 | return 356 | defaultNetworkProfile == cfg.defaultNetworkProfile && 357 | profiles == cfg.profiles && 358 | servers == cfg.servers && 359 | networks == cfg.networks && 360 | defaultNetworkProfile == cfg.defaultNetworkProfile; 361 | } 362 | 363 | bool Config::operator!=(const Config& cfg) const 364 | { 365 | return !(*this == cfg); 366 | } 367 | 368 | void Config::copyProfile(const Config& cfg, Config::NetworkProfile networkProfile) 369 | { 370 | profiles[networkProfile] = cfg.profiles.at(networkProfile); 371 | // At the moment we cannot delete servers or re-order 372 | for (std::size_t i = 0; i < servers.size(); ++i) { 373 | servers[i].setServerDataEqual(cfg.servers[i]); 374 | servers[i].setServerActiveEqualForProfile(cfg.servers[i], networkProfile); 375 | } 376 | } 377 | 378 | bool Config::equalProfile(const Config& cfg, Config::NetworkProfile networkProfile) const 379 | { 380 | 381 | if (!(profiles.at(networkProfile)== cfg.profiles.at(networkProfile))) 382 | return false; 383 | if (servers.size() != cfg.servers.size()) 384 | return false; 385 | // At the moment we cannot delete servers or re-order 386 | for (std::size_t i = 0; i < servers.size(); ++i) { 387 | if (!serverDataIsEqual(servers[i], cfg.servers[i])) 388 | return false; 389 | if (!serverActiveIsEqualForProfile(servers[i], cfg.servers[i], networkProfile)) 390 | return false; 391 | } 392 | return true; 393 | } 394 | 395 | std::string Config::networkProfileDisplayName(Config::NetworkProfile np) 396 | { 397 | switch(np) 398 | { 399 | case Config::NetworkProfile::trusted: 400 | return "Trusted"; 401 | 402 | case Config::NetworkProfile::untrusted: 403 | return "Untrusted"; 404 | 405 | case Config::NetworkProfile::hostile: 406 | return "Hostile"; 407 | } 408 | assert("Unknown network type"); 409 | return "Unknown"; 410 | } 411 | 412 | std::string Config::networkProfileYamlKey(Config::NetworkProfile np) 413 | { 414 | switch(np) 415 | { 416 | case Config::NetworkProfile::trusted: 417 | return "trusted"; 418 | 419 | case Config::NetworkProfile::untrusted: 420 | return "untrusted"; 421 | 422 | case Config::NetworkProfile::hostile: 423 | return "hostile"; 424 | } 425 | assert("Unknown network type"); 426 | return "unknown"; 427 | } 428 | 429 | Config::NetworkProfile Config::networkProfileFromYamlKey(const std::string& key) 430 | { 431 | if ( key == "trusted" ) 432 | return Config::NetworkProfile::trusted; 433 | else if ( key == "untrusted" ) 434 | return Config::NetworkProfile::untrusted; 435 | else if ( key == "hostile" ) 436 | return Config::NetworkProfile::hostile; 437 | else 438 | throw std::invalid_argument(key + " is not a network profile"); 439 | } 440 | 441 | std::string Config::interfaceTypeDisplayName(Config::InterfaceTypes it) 442 | { 443 | switch(it) 444 | { 445 | case Config::InterfaceTypes::WiFi: 446 | return "WiFi"; 447 | 448 | case Config::InterfaceTypes::Ethernet: 449 | return "Ethernet"; 450 | } 451 | assert("Unknown interface type"); 452 | return "unknown"; 453 | } 454 | 455 | std::string Config::networkProfileChoiceDisplayName(Config::NetworkProfileChoice npc) 456 | { 457 | if ( npc == Config::NetworkProfileChoice::default_profile ) 458 | return "Default"; 459 | 460 | return networkProfileDisplayName(networkProfileFromChoice(npc, Config::NetworkProfile::untrusted)); 461 | } 462 | 463 | std::string Config::networkProfileChoiceYamlKey(Config::NetworkProfileChoice npc) 464 | { 465 | if ( npc == Config::NetworkProfileChoice::default_profile ) 466 | return "default"; 467 | 468 | return networkProfileYamlKey(networkProfileFromChoice(npc, Config::NetworkProfile::untrusted)); 469 | } 470 | 471 | Config::NetworkProfileChoice Config::networkProfileChoiceFromYamlKey(const std::string& key) 472 | { 473 | if ( key == "default" ) 474 | return Config::NetworkProfileChoice::default_profile; 475 | else return networkChoiceFromProfile(networkProfileFromYamlKey(key)); 476 | } 477 | 478 | Config::NetworkProfile Config::networkProfileFromChoice(Config::NetworkProfileChoice npc, Config::NetworkProfile default_profile) 479 | { 480 | switch(npc) 481 | { 482 | case Config::NetworkProfileChoice::default_profile: 483 | return default_profile; 484 | 485 | case Config::NetworkProfileChoice::trusted: 486 | return Config::NetworkProfile::trusted; 487 | 488 | case Config::NetworkProfileChoice::untrusted: 489 | return Config::NetworkProfile::untrusted; 490 | 491 | case Config::NetworkProfileChoice::hostile: 492 | return Config::NetworkProfile::hostile; 493 | } 494 | assert("Unknown network type"); 495 | return Config::NetworkProfile::untrusted; 496 | } 497 | 498 | Config::NetworkProfileChoice Config::networkChoiceFromProfile(Config::NetworkProfile np) 499 | { 500 | switch(np) 501 | { 502 | case Config::NetworkProfile::trusted: 503 | return Config::NetworkProfileChoice::trusted; 504 | 505 | case Config::NetworkProfile::untrusted: 506 | return Config::NetworkProfileChoice::untrusted; 507 | 508 | case Config::NetworkProfile::hostile: 509 | return Config::NetworkProfileChoice::hostile; 510 | } 511 | assert("Unknown network type"); 512 | return Config::NetworkProfileChoice::untrusted; 513 | } 514 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef CONFIG_H 10 | #define CONFIG_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct Config 19 | { 20 | enum class NetworkProfile { trusted, untrusted, hostile }; 21 | enum class NetworkProfileChoice { default_profile, trusted, untrusted, hostile }; 22 | 23 | enum class UseNetworkProvidedServer { exclude, include, use_only }; 24 | 25 | struct Server 26 | { 27 | Server(const std::string& name, const std::string& link, const std::vector& addrs, const std::string& authName, const std::string& digest); 28 | Server(); 29 | 30 | std::string name; 31 | std::string link; 32 | std::vector addresses; 33 | std::string tlsAuthName; 34 | std::string pubKeyDigestType; 35 | std::string pubKeyDigestValue; 36 | 37 | std::unordered_set hidden; 38 | std::unordered_set inactive; 39 | 40 | bool operator==(const Server& server) const; 41 | void setServerDataEqual(const Config::Server& server); 42 | void setServerActiveEqualForProfile(const Config::Server& server, Config::NetworkProfile); 43 | }; 44 | 45 | struct Profile 46 | { 47 | Profile (bool encryptAll, bool alwaysAuthenticate, bool validateData, 48 | bool roundRobin, UseNetworkProvidedServer useNetworkProvidedServer); 49 | Profile(); 50 | 51 | bool encryptAll; 52 | bool alwaysAuthenticate; 53 | bool validateData; 54 | bool roundRobin; 55 | UseNetworkProvidedServer useNetworkProvidedServer; 56 | 57 | bool operator==(const Profile& profile) const; 58 | }; 59 | 60 | std::vector servers; 61 | std::unordered_map profiles; 62 | NetworkProfile defaultNetworkProfile; 63 | 64 | typedef enum { 65 | WiFi = 0, 66 | Ethernet 67 | } InterfaceTypes; 68 | 69 | struct NetworkInformation 70 | { 71 | NetworkProfileChoice profile; 72 | InterfaceTypes interfaceType; 73 | bool interfaceActive; 74 | 75 | bool operator==(const NetworkInformation& netinfo) const; 76 | }; 77 | 78 | std::map networks; 79 | 80 | Config(); 81 | void loadFromFile(const std::string& filePath); 82 | void saveToFile(const std::string& filePath) const; 83 | void reset(); 84 | void copyProfile(const Config& cfg, Config::NetworkProfile networkProfile); 85 | 86 | bool operator==(const Config& cfg) const; 87 | bool operator!=(const Config& cfg) const; 88 | bool equalProfile(const Config& cfg, Config::NetworkProfile networkProfile) const; 89 | 90 | bool serverDataIsEqual(const Config::Server& server1, const Config::Server& server2) const; 91 | bool serverActiveIsEqualForProfile(const Config::Server& server1, const Config::Server& server2, Config::NetworkProfile) const; 92 | 93 | static std::string networkProfileDisplayName(NetworkProfile np); 94 | static std::string networkProfileChoiceDisplayName(NetworkProfileChoice npc); 95 | static std::string interfaceTypeDisplayName(InterfaceTypes it); 96 | 97 | static NetworkProfile networkProfileFromChoice(NetworkProfileChoice npc, NetworkProfile default_profile); 98 | static NetworkProfileChoice networkChoiceFromProfile(NetworkProfile np); 99 | 100 | static std::string networkProfileYamlKey(NetworkProfile np); 101 | static NetworkProfile networkProfileFromYamlKey(const std::string& key); 102 | static std::string networkProfileChoiceYamlKey(NetworkProfileChoice npc); 103 | static NetworkProfileChoice networkProfileChoiceFromYamlKey(const std::string& key); 104 | }; 105 | 106 | #endif 107 | 108 | /* Local Variables: */ 109 | /* mode: c++ */ 110 | /* End: */ 111 | -------------------------------------------------------------------------------- /configmanager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "configmanager.h" 21 | #include "mainwindow.h" 22 | 23 | 24 | bool check_config(std::string file) { 25 | QProcess check; 26 | // getdns_query.exe is in the same directory as this executable. 27 | QFileInfo getdns_query = QFileInfo(QDir(QCoreApplication::applicationDirPath()), "stubby.exe"); 28 | QStringList arguments; 29 | arguments << "-i" << "-C" << file.c_str(); 30 | check.setProgram(getdns_query.filePath()); 31 | check.setArguments(arguments); 32 | check.start(); 33 | if (!check.waitForStarted()) 34 | return false; 35 | if (!check.waitForFinished()) 36 | return false; 37 | QByteArray stdoutData; 38 | int exitcode = check.exitCode(); 39 | qInfo("check_config result is %d", exitcode); 40 | //qDebug() << __FILE__ << ":" << __FUNCTION__ << stdoutData; 41 | return exitcode; 42 | } 43 | 44 | ConfigMgr::ConfigMgr(MainWindow *parent) 45 | : QObject(parent), m_mainwindow(parent), restartRequired(false) 46 | { 47 | qInfo("Creating config mgr"); 48 | } 49 | 50 | ConfigMgr::~ConfigMgr() 51 | { 52 | } 53 | 54 | const std::string ConfigMgr::APPDIRNAME = "Stubby"; 55 | const std::string ConfigMgr::NETPROFILENAME = "netprofile.yml"; 56 | const std::string ConfigMgr::DEFNETPROFILENAME = "netprofile_defaults.yml"; 57 | const std::string ConfigMgr::STUBBYTEMPLATENAME = "stubbytemplate.yml"; 58 | 59 | void ConfigMgr::init() 60 | { 61 | QDir factoryDir(QString::fromStdString(appDataDir())); 62 | QFileInfo factoryConfigFile(factoryDir, QString::fromStdString(DEFNETPROFILENAME)); 63 | 64 | if ( factoryConfigFile.isFile() && factoryConfigFile.isReadable() ) 65 | { 66 | try { 67 | factoryConfig.loadFromFile(factoryConfigFile.filePath().toStdString()); 68 | qInfo("Read default config file."); 69 | } catch (...) { 70 | m_mainwindow->statusMsg("ERROR: Unable to load default configuration file, using built-in defaults"); 71 | qWarning("No readable default configuration file, using built-in defaults"); 72 | factoryConfig.reset(); 73 | } 74 | emit configChanged(false); 75 | return; 76 | } 77 | m_mainwindow->statusMsg("WARNING: No default configuration file available, using built-in defaults"); 78 | qWarning("No readable default configuration file, using built-in defaults"); 79 | factoryConfig.reset(); 80 | return; 81 | } 82 | 83 | void ConfigMgr::load() 84 | { 85 | displayedConfig = factoryConfig; 86 | 87 | QDir customDir(QString::fromStdString(appDataDir())); 88 | QFileInfo customConfigFile(customDir, QString::fromStdString(NETPROFILENAME)); 89 | 90 | if ( customConfigFile.isFile() && customConfigFile.isReadable() ) 91 | { 92 | try { 93 | savedConfig.loadFromFile(customConfigFile.filePath().toStdString()); 94 | displayedConfig = savedConfig; 95 | qInfo("Read custom config file."); 96 | } catch (...) { 97 | m_mainwindow->statusMsg("ERROR: Unable to load user configuration file, using default conifguration instead."); 98 | m_mainwindow->systrayMsg("ERROR: Unable to load user configuration file, using default conifguration instead."); 99 | // TODO: we should think about renaming the broken config file for later inspection, we need to overwrite 100 | // it so a saved config isgenreatedand the GUI doesn't break on an empty one.... 101 | } 102 | } 103 | saveAll(false); 104 | emit configChanged(false); 105 | qWarning("No readable custom configuration file"); 106 | } 107 | 108 | std::string ConfigMgr::getCurrentProfileString() const { 109 | std::string profile_string = Config::networkProfileDisplayName(m_current_profile); 110 | if (m_current_profile == savedConfig.defaultNetworkProfile) 111 | profile_string.append(" (Default)"); 112 | return profile_string; 113 | } 114 | 115 | std::string ConfigMgr::getCurrentNetworksString() const { 116 | return m_current_networks_string; 117 | } 118 | 119 | bool ConfigMgr::profilesValid(Config::NetworkProfile check_profile, bool check_all) { 120 | std::unordered_map profiles = displayedConfig.profiles; 121 | for (const auto& profile : profiles) { 122 | Config::NetworkProfile prof_type = profile.first; 123 | if (!check_all && prof_type != check_profile) 124 | continue; 125 | int server_count=0; 126 | int server_auth=0; 127 | int server_cleartext=0; 128 | for ( const auto& s : displayedConfig.servers ) 129 | { 130 | if ( s.hidden.find(prof_type) != s.hidden.end() || 131 | s.inactive.find(prof_type) != s.inactive.end() ) 132 | continue; 133 | 134 | server_count++; 135 | for ( const auto& a : s.addresses ) 136 | { 137 | if (!s.tlsAuthName.empty() || !s.pubKeyDigestValue.empty()) 138 | server_auth++; 139 | if (a.compare("1.1.1.1") == 0 || a.compare("9.9.9.9") == 0 || 140 | a.compare("8.8.8.8") == 0 || a.compare("176.103.130.130") == 0 || a.compare("89.233.43.71") == 0) { 141 | server_cleartext++; 142 | } 143 | } 144 | } 145 | // 1) must be at least one server 146 | if (server_count == 0) { 147 | QString message = "ERROR: The "; 148 | message.append(Config::networkProfileDisplayName(prof_type).c_str()); 149 | message.append(" profile cannot be saved: there must be at least one server in a profile."); 150 | m_mainwindow->systrayMsg(message); 151 | return false; 152 | } 153 | // 2) If authenticate then must be at least one server with auth creds 154 | if (profile.second.encryptAll && profile.second.alwaysAuthenticate && server_auth == 0) { 155 | QString message = "ERROR: The "; 156 | message.append(Config::networkProfileDisplayName(prof_type).c_str()); 157 | message.append(" profile cannot be saved: there must be at least one server with either an authentication name or a pinset in a profile that requires authentication."); 158 | m_mainwindow->systrayMsg(message); 159 | return false; 160 | } 161 | // 3) Warn if not encryption and none of the shipped servers that do cleartext are included 162 | if (!profile.second.encryptAll && server_cleartext == 0 ){ 163 | //&& 164 | //profile.second.useNetworkProvidedServer == Config::UseNetworkProvidedServer::exclude) { 165 | QString message = "WARNING: The "; 166 | message.append(Config::networkProfileDisplayName(prof_type).c_str()); 167 | message.append(" profile is set not to encrypt traffic, but none of the shipped servers known to support cleartext are included."); 168 | m_mainwindow->systrayMsg(message); 169 | return false; 170 | } 171 | } 172 | return true; 173 | } 174 | 175 | 176 | bool ConfigMgr::saveAll(bool restart) 177 | { 178 | if (!profilesValid(Config::NetworkProfile::untrusted, true)) 179 | return false; 180 | tempConfig = savedConfig; 181 | savedConfig = displayedConfig; 182 | saveConfig(savedConfig); 183 | return true; 184 | } 185 | 186 | bool ConfigMgr::saveProfile(Config::NetworkProfile networkProfile) 187 | { 188 | if (!profilesValid(networkProfile, false)) 189 | return false; 190 | tempConfig = savedConfig; 191 | savedConfig.copyProfile(displayedConfig, networkProfile); 192 | saveConfig(savedConfig); 193 | return true; 194 | } 195 | 196 | void ConfigMgr::saveNetworks() 197 | { 198 | tempConfig = savedConfig; 199 | savedConfig.networks = displayedConfig.networks; 200 | savedConfig.defaultNetworkProfile = displayedConfig.defaultNetworkProfile; 201 | saveConfig(savedConfig); 202 | } 203 | 204 | void ConfigMgr::saveUpdatedNetworks() 205 | { 206 | tempConfig = savedConfig; 207 | if (saveConfig(savedConfig)) 208 | m_mainwindow->alertOnNetworksUpdatedRestart(); 209 | } 210 | 211 | bool ConfigMgr::saveConfig(const Config& config) 212 | { 213 | 214 | Config::NetworkProfile temp_current_profile = m_current_profile; 215 | m_current_networks_string=""; 216 | m_current_profile=Config::NetworkProfile::trusted; 217 | for ( const auto& net : config.networks ) { 218 | auto net_name = net.first; 219 | auto net_active = net.second.interfaceActive; 220 | Config::NetworkProfile profile = Config::networkProfileFromChoice(net.second.profile, config.defaultNetworkProfile); 221 | // Only disply the active networks 222 | if (net_active) { 223 | if ( !m_current_networks_string.empty()) 224 | m_current_networks_string.append("\n"); 225 | m_current_networks_string.append(net_name); 226 | qInfo("SAVING: network %s has profile %d", net_name.c_str(), profile); 227 | if ( profile > m_current_profile ) 228 | m_current_profile = profile; 229 | } 230 | } 231 | 232 | QDir customDir(QString::fromStdString(appDataDir())); 233 | QFileInfo customConfig(customDir, QString::fromStdString(NETPROFILENAME)); 234 | QDir::root().mkpath(customDir.absolutePath()); 235 | config.saveToFile(customConfig.filePath().toStdString()); 236 | 237 | // is restart needed? 238 | int restart = false; 239 | if (temp_current_profile != m_current_profile) { 240 | qInfo("RESTART: Restart required if running - active profile changed from %s to %s", 241 | Config::networkProfileDisplayName(temp_current_profile).c_str(), 242 | Config::networkProfileDisplayName(m_current_profile).c_str()); 243 | restart = true; 244 | } 245 | else if (!savedConfig.equalProfile(tempConfig, m_current_profile)) 246 | restart = true; 247 | 248 | emit configChanged(restart); 249 | return restart; 250 | } 251 | 252 | std::string ConfigMgr::generateStubbyConfig() 253 | { 254 | 255 | // Look for template file in factory dir and current dir. 256 | QDir tpldir(QString::fromStdString(appDataDir())); 257 | QFileInfo tpl(tpldir, QString::fromStdString(STUBBYTEMPLATENAME)); 258 | 259 | if ( !tpl.isFile() || !tpl.isReadable() ) 260 | { 261 | tpl = QFileInfo(QDir(QCoreApplication::applicationDirPath()), QString::fromStdString(STUBBYTEMPLATENAME)); 262 | if ( !tpl.isFile() || !tpl.isReadable() ) 263 | throw std::runtime_error("Stubby template file not found"); 264 | } 265 | 266 | QDir tmpdir(QString::fromStdString(appDir())); 267 | if ( !QDir::root().mkpath(tmpdir.absolutePath()) ) 268 | throw std::runtime_error("Can't make application temporary directory"); 269 | QFileInfo stubby_yml(tmpdir, "stubbyservice_tmp.yml"); 270 | QFileInfo stubby_yml_real(tmpdir, "stubbyservice.yml"); 271 | 272 | ctemplate::TemplateDictionary dict("STUBBY_CONFIG"); 273 | if ( savedConfig.profiles[m_current_profile].encryptAll ) 274 | dict.SetValue("TRANSPORT_LIST", "[GETDNS_TRANSPORT_TLS]"); 275 | else 276 | dict.SetValue("TRANSPORT_LIST", "[GETDNS_TRANSPORT_TLS, GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP]"); 277 | if ( savedConfig.profiles[m_current_profile].alwaysAuthenticate ) 278 | dict.SetValue("AUTHENTICATION", "GETDNS_AUTHENTICATION_REQUIRED"); 279 | else 280 | dict.SetValue("AUTHENTICATION", "GETDNS_AUTHENTICATION_NONE"); 281 | if ( savedConfig.profiles[m_current_profile].validateData ) 282 | dict.SetValue("DNSSEC", "GETDNS_EXTENSION_TRUE"); 283 | else 284 | dict.SetValue("DNSSEC", "GETDNS_EXTENSION_FALSE"); 285 | if ( savedConfig.profiles[m_current_profile].roundRobin ) 286 | dict.SetValue("ROUND_ROBIN", "1"); 287 | else 288 | dict.SetValue("ROUND_ROBIN", "0"); 289 | 290 | int server_count=0; 291 | for ( const auto& s : savedConfig.servers ) 292 | { 293 | if ( s.hidden.find(m_current_profile) != s.hidden.end() || 294 | s.inactive.find(m_current_profile) != s.inactive.end() ) 295 | continue; 296 | 297 | server_count++; 298 | for ( const auto& a : s.addresses ) 299 | { 300 | ctemplate::TemplateDictionary* subdict = dict.AddSectionDictionary("SERVER"); 301 | subdict->SetValue("SERVER_ADDRESS", a); 302 | if (!s.tlsAuthName.empty()) { 303 | ctemplate::TemplateDictionary* sub_dict1 = subdict->AddSectionDictionary("AUTHNAME"); 304 | sub_dict1->SetValue("SERVER_AUTH_NAME", s.tlsAuthName); 305 | } 306 | if (!s.pubKeyDigestValue.empty()) { 307 | ctemplate::TemplateDictionary* sub_dict2 = subdict->AddSectionDictionary("PINSET"); 308 | sub_dict2->SetValue("SERVER_DIGEST_TYPE", s.pubKeyDigestType); 309 | sub_dict2->SetValue("SERVER_DIGEST_VALUE", s.pubKeyDigestValue); 310 | } 311 | } 312 | } 313 | 314 | //Basic check that the config is valid with 1 server. 315 | // TODO: Proper crosscheck of validity at save time 316 | if (server_count == 0) 317 | return ""; 318 | 319 | std::string expansion; 320 | if ( !ctemplate::ExpandTemplate(tpl.filePath().toStdString(), ctemplate::STRIP_BLANK_LINES, &dict, &expansion) ) 321 | throw std::runtime_error("Template expansion failed"); 322 | 323 | std::string res = stubby_yml.filePath().toStdString(); 324 | std::ofstream fout(res); 325 | fout.exceptions(std::ofstream::failbit | std::ofstream::badbit); 326 | fout << expansion; 327 | fout.close(); 328 | 329 | // now check the file is valid 330 | if (check_config(res) != 0) { 331 | return ""; 332 | } 333 | 334 | // copy to real location, leave tmp file for potential debugging 335 | std::ifstream src(res, std::ios::binary); 336 | std::ofstream dst(stubby_yml_real.filePath().toStdString(), std::ios::binary); 337 | dst << src.rdbuf(); 338 | return stubby_yml_real.filePath().toStdString(); 339 | } 340 | 341 | std::string ConfigMgr::appDir() 342 | { 343 | return QDir(QDir::tempPath()).filePath(QString::fromStdString(APPDIRNAME)).toStdString(); 344 | } 345 | 346 | bool ConfigMgr::profileModifiedFromFactory(Config::NetworkProfile networkProfile) 347 | { 348 | return profileModifiedFrom(factoryConfig, networkProfile); 349 | } 350 | 351 | bool ConfigMgr::profileModifiedFromSaved(Config::NetworkProfile networkProfile) 352 | { 353 | return profileModifiedFrom(savedConfig, networkProfile); 354 | } 355 | 356 | bool ConfigMgr::networksModifiedFromSaved() 357 | { 358 | return networksModifiedFrom(savedConfig); 359 | } 360 | 361 | bool ConfigMgr::modifiedFromFactoryDefaults() 362 | { 363 | return modifiedFrom(factoryConfig); 364 | } 365 | 366 | bool ConfigMgr::modifiedFromSavedConfig() 367 | { 368 | return modifiedFrom(savedConfig); 369 | } 370 | 371 | void ConfigMgr::profileRestoreSaved(Config::NetworkProfile networkProfile) 372 | { 373 | profileRestoreFrom(savedConfig, networkProfile); 374 | } 375 | 376 | void ConfigMgr::profileRestoreFactory(Config::NetworkProfile networkProfile) 377 | { 378 | profileRestoreFrom(factoryConfig, networkProfile); 379 | } 380 | 381 | void ConfigMgr::networksRestoreSaved() 382 | { 383 | networksRestoreFrom(savedConfig); 384 | } 385 | 386 | void ConfigMgr::restoreSaved() 387 | { 388 | restoreFrom(savedConfig); 389 | } 390 | 391 | void ConfigMgr::restoreFactory() 392 | { 393 | restoreFrom(factoryConfig); 394 | } 395 | 396 | bool ConfigMgr::profileModifiedFrom(const Config& cfg, Config::NetworkProfile networkProfile) 397 | { 398 | return !displayedConfig.equalProfile(cfg, networkProfile); 399 | } 400 | 401 | bool ConfigMgr::networksModifiedFrom(const Config& cfg) 402 | { 403 | return 404 | cfg.networks != displayedConfig.networks || 405 | cfg.defaultNetworkProfile != displayedConfig.defaultNetworkProfile; 406 | } 407 | 408 | bool ConfigMgr::modifiedFrom(const Config& cfg) 409 | { 410 | return cfg != displayedConfig; 411 | } 412 | 413 | void ConfigMgr::profileRestoreFrom(const Config& cfg, Config::NetworkProfile networkProfile) 414 | { 415 | displayedConfig.copyProfile(cfg, networkProfile); 416 | emit configChanged(false); 417 | } 418 | 419 | void ConfigMgr::networksRestoreFrom(const Config& cfg) 420 | { 421 | displayedConfig.networks = cfg.networks; 422 | displayedConfig.defaultNetworkProfile = cfg.defaultNetworkProfile; 423 | emit configChanged(false); 424 | } 425 | 426 | void ConfigMgr::restoreFrom(const Config& cfg) 427 | { 428 | displayedConfig = cfg; 429 | emit configChanged(false); 430 | } 431 | 432 | Config::NetworkProfile ConfigMgr::addNetwork(const std::string& name, NetworkMgr::InterfaceTypes type, bool active) 433 | { 434 | // For now, since the user must have a default use this code to catch any corner case 435 | if ( displayedConfig.networks.find(name) == displayedConfig.networks.end() ) { 436 | displayedConfig.networks[name].profile = Config::NetworkProfileChoice::default_profile; 437 | displayedConfig.networks[name].interfaceType=Config::InterfaceTypes(type); 438 | } 439 | // always update the active status in case it has changed 440 | displayedConfig.networks[name].interfaceActive=active; 441 | 442 | if ( savedConfig.networks.find(name) == savedConfig.networks.end() ) { 443 | savedConfig.networks[name].profile = Config::NetworkProfileChoice::default_profile; 444 | savedConfig.networks[name].interfaceType=Config::InterfaceTypes(type); 445 | m_mainwindow->alertOnNewNetwork(name, savedConfig.defaultNetworkProfile); 446 | } 447 | savedConfig.networks[name].interfaceActive=active; 448 | return Config::networkProfileFromChoice(savedConfig.networks[name].profile, savedConfig.defaultNetworkProfile); 449 | } 450 | 451 | void ConfigMgr::updateNetworks(std::map running_networks) { 452 | 453 | // Set all networks to inactive, to ensure only active ones are set below 454 | for ( auto& a : savedConfig.networks) { 455 | a.second.interfaceActive = false; 456 | } 457 | for ( auto& a : displayedConfig.networks) { 458 | a.second.interfaceActive = false; 459 | } 460 | 461 | for ( const auto& net : running_networks ) { 462 | // Ignore the wifi when it is not connected as it has no ssid 463 | if (net.first.compare("Wi-Fi") == 0) { 464 | continue; 465 | } 466 | // This actually also updates the active status of the existing network..... 467 | Config::NetworkProfile profile = addNetwork(net.first, net.second.interfaceType, net.second.interfaceActive); 468 | } 469 | saveUpdatedNetworks(); 470 | } 471 | 472 | -------------------------------------------------------------------------------- /configmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef CONFIGMGR_H 10 | #define CONFIGMGR_H 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "config.h" 18 | #include "networkmanager.h" 19 | 20 | class MainWindow; 21 | 22 | class ConfigMgr : public QObject 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | ConfigMgr(MainWindow *parent); 28 | virtual ~ConfigMgr(); 29 | 30 | static const std::string APPDIRNAME; 31 | static const std::string NETPROFILENAME; 32 | static const std::string DEFNETPROFILENAME; 33 | static const std::string STUBBYTEMPLATENAME; 34 | 35 | static ConfigMgr * factory(MainWindow *parent); 36 | 37 | Config displayedConfig; 38 | 39 | void init(); 40 | void load(); 41 | bool saveAll(bool restart); 42 | bool saveProfile(Config::NetworkProfile networkProfile); 43 | void saveNetworks(); 44 | void saveUpdatedNetworks(); 45 | 46 | std::string generateStubbyConfig(); 47 | 48 | bool profileModifiedFromFactory(Config::NetworkProfile networkProfile); 49 | bool profileModifiedFromSaved(Config::NetworkProfile networkProfile); 50 | bool networksModifiedFromSaved(); 51 | bool modifiedFromFactoryDefaults(); 52 | bool modifiedFromSavedConfig(); 53 | 54 | void profileRestoreSaved(Config::NetworkProfile networkProfile); 55 | void profileRestoreFactory(Config::NetworkProfile networkProfile); 56 | void networksRestoreSaved(); 57 | void restoreSaved(); 58 | void restoreFactory(); 59 | 60 | void updateNetworks(std::map running_networks); 61 | std::string getCurrentProfileString() const; 62 | std::string getCurrentNetworksString() const; 63 | 64 | signals: 65 | void configChanged(bool restart); 66 | 67 | protected: 68 | bool profileModifiedFrom(const Config& cfg, Config::NetworkProfile networkProfile); 69 | bool networksModifiedFrom(const Config& cfg); 70 | bool modifiedFrom(const Config& cfg); 71 | void profileRestoreFrom(const Config& cfg, Config::NetworkProfile networkProfile); 72 | void networksRestoreFrom(const Config& cfg); 73 | void restoreFrom(const Config& cfg); 74 | bool saveConfig(const Config& cfg); 75 | bool profilesValid(Config::NetworkProfile profile, bool check_all); 76 | Config::NetworkProfile addNetwork(const std::string& name, NetworkMgr::InterfaceTypes type, bool active); 77 | 78 | MainWindow *m_mainwindow; 79 | Config factoryConfig; 80 | Config savedConfig; 81 | Config tempConfig; // used to determine if restart needed 82 | bool restartRequired; 83 | Config::NetworkProfile m_current_profile; 84 | std::string m_current_networks_string; 85 | 86 | virtual std::string appDataDir() = 0; 87 | virtual std::string appDir(); 88 | }; 89 | 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /images/getdns_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/getdns_logo.png -------------------------------------------------------------------------------- /images/off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/off.png -------------------------------------------------------------------------------- /images/on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/on.png -------------------------------------------------------------------------------- /images/stubby.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/stubby.ico -------------------------------------------------------------------------------- /images/stubby@245x145.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/stubby@245x145.png -------------------------------------------------------------------------------- /images/stubby@245x145_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/stubby@245x145_green.png -------------------------------------------------------------------------------- /images/stubby@245x145_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/images/stubby@245x145_red.png -------------------------------------------------------------------------------- /logmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef LOGMANAGER_H 10 | #define LOGMANAGER_H 11 | 12 | class MainWindow; 13 | 14 | namespace Ui { 15 | class ILogMgr; 16 | } 17 | 18 | class ILogMgr 19 | { 20 | public: 21 | virtual ~ILogMgr() = default; 22 | 23 | static ILogMgr * factory(MainWindow *parent); 24 | 25 | virtual void start() = 0; 26 | virtual void stop() = 0; 27 | 28 | signals: 29 | virtual void alert(bool on) = 0; 30 | }; 31 | 32 | #define LogMgr_iid "com.sinodun.stubby.LogMgr" 33 | Q_DECLARE_INTERFACE(ILogMgr, LogMgr_iid) 34 | 35 | #endif // LOGMANAGER_H 36 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include "mainwindow.h" 10 | 11 | #include 12 | 13 | #ifndef QT_NO_SYSTEMTRAYICON 14 | 15 | #include 16 | #include 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | Q_INIT_RESOURCE(stubby); 21 | 22 | QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 23 | 24 | QApplication::setStyle(QStyleFactory::create("Fusion")); 25 | QApplication a(argc, argv); 26 | 27 | if (!QSystemTrayIcon::isSystemTrayAvailable()) { 28 | QMessageBox::critical(0, QObject::tr("Systray"), 29 | QObject::tr("I couldn't detect any system tray " 30 | "on this system.")); 31 | return 1; 32 | } 33 | QApplication::setQuitOnLastWindowClosed(false); 34 | 35 | MainWindow w; 36 | w.show(); 37 | return a.exec(); 38 | } 39 | 40 | 41 | #else 42 | 43 | #include 44 | #include 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | QApplication app(argc, argv); 49 | QString text("QSystemTrayIcon is not supported on this platform"); 50 | 51 | QLabel *label = new QLabel(text); 52 | label->setWordWrap(true); 53 | 54 | label->show(); 55 | qDebug() << text; 56 | 57 | app.exec(); 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef MAINWINDOW_H 10 | #define MAINWINDOW_H 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #include "configmanager.h" 20 | #include "servicemanager.h" 21 | #include "networkmanager.h" 22 | #include "networkprofilewidget.h" 23 | #include "networkswidget.h" 24 | #include "logmanager.h" 25 | 26 | QT_BEGIN_NAMESPACE 27 | namespace Ui { class MainWindow; } 28 | QT_END_NAMESPACE 29 | 30 | 31 | class MainWindow : public QMainWindow 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | MainWindow(QWidget *parent = nullptr); 37 | ~MainWindow(); 38 | 39 | void statusMsg(QString status_msg); 40 | void systrayMsg(QString status_msg); 41 | void systrayAlert(QString status_msg); 42 | void logMsg(QString log_msg); 43 | enum UpdateState{Init, Start, Stop, Restart, Probe, None}; 44 | int getUpdateState() const {return updateState;}; 45 | bool isServiceRunning() const; 46 | void refreshNetworks(std::map running_networks); 47 | void alertOnNetworksUpdatedRestart(); 48 | void alertOnNewNetwork(std::string network, Config::NetworkProfile profile); 49 | 50 | protected: 51 | void closeEvent(QCloseEvent *event) override; 52 | 53 | 54 | private slots: 55 | 56 | void on_hideDetailsCheckBox_toggled(); 57 | void on_onOffSlider_stateChanged(); 58 | void on_restartButton_clicked(); 59 | void on_probeButton_clicked(); 60 | void on_testButton_clicked(); 61 | void on_testQueryResult(bool result); 62 | void on_showLogButton_toggled(); 63 | void on_helpButton_clicked(); 64 | void on_applyAllButton_clicked(); 65 | void on_discardAllButton_clicked(); 66 | void on_revertAllButton_clicked(); 67 | 68 | void on_serviceStateChanged(ServiceMgr::ServiceState state); 69 | void on_DNSStateChanged(NetworkMgr::NetworkState state); 70 | 71 | void on_userProfileEditInProgress(); 72 | void on_userNetworksEditInProgress(); 73 | void on_SavedConfigChanged(bool restart); 74 | 75 | void closeFromSystray(); 76 | void iconActivated(QSystemTrayIcon::ActivationReason reason); 77 | 78 | private: 79 | void setMainButtonStates(); 80 | void setTopPanelStatus(); 81 | void setTopPanelNetworkInfo(); 82 | void firstRunPopUp(); 83 | void setToolTips(); 84 | 85 | void timerExpired(); 86 | void probeTimerExpired(); 87 | void handleError(); 88 | void handleCancel(); 89 | int handleUnsavedChanges(); 90 | 91 | 92 | Ui::MainWindow *ui; 93 | 94 | ConfigMgr *m_configMgr; 95 | ServiceMgr *m_serviceMgr; 96 | ServiceMgr::ServiceState m_serviceState; 97 | QString getServiceStateString(const ServiceMgr::ServiceState state); 98 | 99 | NetworkMgr *m_networkMgr; 100 | NetworkMgr::NetworkState m_networkState; 101 | QString getNetworkStateString(const NetworkMgr::NetworkState state); 102 | 103 | NetworkProfileWidget *m_untrustedNetworkWidget; 104 | NetworkProfileWidget *m_trustedNetworkWidget; 105 | NetworkProfileWidget *m_hostileNetworkWidget; 106 | 107 | NetworksWidget *m_networksWidget; 108 | 109 | ILogMgr *m_logMgr; 110 | 111 | UpdateState updateState; 112 | 113 | QTimer *timer; 114 | QTimer *probeTimer; 115 | 116 | QAction *quitAction; 117 | QAction *openAction; 118 | QSystemTrayIcon *trayIcon; 119 | QMenu *trayIconMenu; 120 | QSettings *stubbySettings; 121 | 122 | QPixmap *greenPixmap; 123 | QPixmap *yellowPixmap; 124 | QPixmap *redPixmap; 125 | QPixmap *greyPixmap; 126 | 127 | }; 128 | #endif // MAINWINDOW_H 129 | -------------------------------------------------------------------------------- /netprofile_defaults.yml: -------------------------------------------------------------------------------- 1 | servers: 2 | - name: Stubby server (getdnsapi.net) 3 | link: dnsprivacy.org/wiki/x/E4AT 4 | addresses: 5 | - 185.49.141.37 6 | tls_auth_name: getdnsapi.net 7 | tls_pubkey_pinset: 8 | digest: sha256 9 | value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q= 10 | hidden: 11 | [] 12 | inactive: 13 | - hostile 14 | - trusted 15 | - name: Quad9 (9.9.9.9) 16 | link: quad9.net 17 | addresses: 18 | - 9.9.9.9 19 | tls_auth_name: dns.quad9.net 20 | tls_pubkey_pinset: 21 | digest: sha256 22 | value: "" 23 | hidden: 24 | [] 25 | inactive: 26 | - untrusted 27 | - name: Comcast 28 | link: corporate.comcast.com/privacy 29 | addresses: 30 | - 96.113.151.145 31 | tls_auth_name: dot.xfinity.com 32 | tls_pubkey_pinset: 33 | digest: sha256 34 | value: "" 35 | hidden: 36 | [] 37 | inactive: 38 | - trusted 39 | - untrusted 40 | - hostile 41 | - name: Cloudflare (1.1.1.1) 42 | link: developers.cloudflare.com/1.1.1.1 43 | addresses: 44 | - 1.1.1.1 45 | tls_auth_name: cloudflare-dns.com 46 | tls_pubkey_pinset: 47 | digest: sha256 48 | value: "" 49 | hidden: 50 | [] 51 | inactive: 52 | - trusted 53 | - untrusted 54 | - hostile 55 | - name: Google (8.8.8.8) 56 | link: developers.google.com/speed/public-dns 57 | addresses: 58 | - 8.8.8.8 59 | tls_auth_name: dns.google 60 | tls_pubkey_pinset: 61 | digest: sha256 62 | value: "" 63 | hidden: 64 | [] 65 | inactive: 66 | - trusted 67 | - untrusted 68 | - hostile 69 | - name: Foundation for Applied Privacy 70 | link: appliedprivacy.net/services/dns/ 71 | addresses: 72 | - 146.255.56.98 73 | tls_auth_name: dot1.applied-privacy.net 74 | tls_pubkey_pinset: 75 | digest: sha256 76 | value: "" 77 | hidden: 78 | [] 79 | inactive: 80 | - trusted 81 | - untrusted 82 | - hostile 83 | - name: CleanBrownsing 84 | link: cleanbrowsing.org/privacy 85 | addresses: 86 | - 85.228.168.9 87 | tls_auth_name: family-filter-dns.cleanbrowsing.org 88 | tls_pubkey_pinset: 89 | digest: sha256 90 | value: "" 91 | hidden: 92 | [] 93 | inactive: 94 | - trusted 95 | - untrusted 96 | - hostile 97 | - name: AgGuard 98 | link: adguard.com/en/privacy.html 99 | addresses: 100 | - 176.103.130.130 101 | tls_auth_name: dns.adguard.com 102 | tls_pubkey_pinset: 103 | digest: sha256 104 | value: "" 105 | hidden: 106 | [] 107 | inactive: 108 | - trusted 109 | - untrusted 110 | - hostile 111 | - name: UncensoredDNS 112 | link: blog.uncensoreddns.org/ 113 | addresses: 114 | - 89.233.43.71 115 | tls_auth_name: unicast.censurfridns.dk 116 | tls_pubkey_pinset: 117 | digest: sha256 118 | value: "" 119 | hidden: 120 | [] 121 | inactive: 122 | - trusted 123 | - untrusted 124 | - hostile 125 | profiles: 126 | trusted: 127 | encrypt_all: false 128 | always_authenticate: false 129 | validate_data: false 130 | round_robin: false 131 | user_network_provided_servers: use-only 132 | untrusted: 133 | encrypt_all: true 134 | always_authenticate: true 135 | validate_data: false 136 | round_robin: false 137 | user_network_provided_servers: include 138 | hostile: 139 | encrypt_all: true 140 | always_authenticate: true 141 | validate_data: false 142 | round_robin: false 143 | user_network_provided_servers: exclude 144 | default_network_profile: untrusted 145 | default_network_profile_set: true 146 | networks: 147 | {} -------------------------------------------------------------------------------- /networkinterface.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKINTERFACE_HPP 10 | #define NETWORKINTERFACE_HPP 11 | 12 | #include 13 | 14 | class NetworkInterface 15 | { 16 | public: 17 | virtual ~NetworkInterface() = default; 18 | 19 | virtual std::string name() const = 0; 20 | 21 | virtual bool is_resolver_loopback() const = 0; 22 | virtual bool is_running() const = 0; 23 | virtual bool is_up() const = 0; 24 | virtual bool is_wireless() const = 0; 25 | virtual bool is_ethernet() const = 0; 26 | virtual std::string ssid() const = 0; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /networkmanager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "mainwindow.h" 13 | 14 | 15 | NetworkMgr::NetworkMgr(MainWindow *parent) : 16 | QObject(parent), 17 | m_mainwindow(parent), 18 | m_networkState(NetworkMgr::Unknown) 19 | 20 | { 21 | qInfo("Creating network mgr"); 22 | } 23 | 24 | NetworkMgr::~NetworkMgr() 25 | { 26 | } 27 | 28 | int NetworkMgr::setLocalhost() 29 | { 30 | m_mainwindow->statusMsg("Action: Setting system to use Stubby service (setting DNS to localhost...)"); 31 | return setLocalhostDNS(); 32 | } 33 | 34 | int NetworkMgr::unsetLocalhost() 35 | { 36 | m_mainwindow->statusMsg("Action: Setting system NOT to use Stubby service (setting DNS back to system settings..."); 37 | return unsetLocalhostDNS(); 38 | } 39 | 40 | int NetworkMgr::getDNSState(bool reportNoChange) 41 | { 42 | return getStateDNS(reportNoChange); 43 | } 44 | 45 | std::map NetworkMgr::getRunningNetworks() { 46 | return getNetworks(); 47 | } 48 | -------------------------------------------------------------------------------- /networkmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKMGR_H 10 | #define NETWORKMGR_H 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | class MainWindow; 18 | 19 | 20 | class NetworkMgr : public QObject 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | NetworkMgr(MainWindow *parent); 26 | virtual ~NetworkMgr(); 27 | 28 | static NetworkMgr * factory(MainWindow *parent); 29 | 30 | typedef enum { 31 | NotLocalhost = 0, 32 | Localhost, 33 | Unknown 34 | } NetworkState; 35 | 36 | typedef enum { 37 | WiFi = 0, 38 | Ethernet 39 | } InterfaceTypes; 40 | 41 | struct interfaceInfo 42 | { 43 | InterfaceTypes interfaceType; 44 | bool interfaceActive; 45 | }; 46 | 47 | int setLocalhost(); 48 | int unsetLocalhost(); 49 | int getDNSState(bool reportNoChange); 50 | virtual int testQuery() = 0; 51 | std::map getRunningNetworks(); 52 | 53 | signals: 54 | void DNSStateChanged(NetworkMgr::NetworkState state); 55 | void testQueryResult(bool result); 56 | 57 | protected: 58 | virtual int setLocalhostDNS() = 0; 59 | virtual int unsetLocalhostDNS() = 0; 60 | virtual int getStateDNS(bool reportNoChange) = 0; 61 | virtual std::map getNetworks() = 0; 62 | MainWindow *m_mainwindow; 63 | NetworkState m_networkState; 64 | 65 | }; 66 | 67 | #endif // NETWORKMGR_H 68 | -------------------------------------------------------------------------------- /networkprofiledelegate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include "config.h" 12 | #include "networkprofiledelegate.h" 13 | 14 | NetworkProfileDelegate::NetworkProfileDelegate(QObject* parent) 15 | : QStyledItemDelegate(parent) 16 | { 17 | } 18 | 19 | QWidget* NetworkProfileDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& /* option */, const QModelIndex& /* index */) const 20 | { 21 | QComboBox* cb = new QComboBox(parent); 22 | 23 | cb->addItem(QString::fromStdString(Config::networkProfileChoiceDisplayName(Config::NetworkProfileChoice::default_profile))); 24 | cb->addItem(QString::fromStdString(Config::networkProfileChoiceDisplayName(Config::NetworkProfileChoice::trusted))); 25 | cb->addItem(QString::fromStdString(Config::networkProfileChoiceDisplayName(Config::NetworkProfileChoice::untrusted))); 26 | cb->addItem(QString::fromStdString(Config::networkProfileChoiceDisplayName(Config::NetworkProfileChoice::hostile))); 27 | return cb; 28 | } 29 | 30 | void NetworkProfileDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const 31 | { 32 | QComboBox* cb = qobject_cast(editor); 33 | Q_ASSERT(cb); 34 | cb->setCurrentIndex(index.data(Qt::EditRole).toInt()); 35 | } 36 | 37 | void NetworkProfileDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const 38 | { 39 | QComboBox* cb = qobject_cast(editor); 40 | Q_ASSERT(cb); 41 | model->setData(index, cb->currentIndex(), Qt::EditRole); 42 | } 43 | -------------------------------------------------------------------------------- /networkprofiledelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKPROFILEDELEGATE_H 10 | #define NETWORKPROFILEDELEGATE_H 11 | 12 | #include 13 | 14 | class NetworkProfileDelegate : public QStyledItemDelegate 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | NetworkProfileDelegate(QObject* parent = nullptr); 20 | 21 | QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; 22 | void setEditorData(QWidget *editor, const QModelIndex &index) const override; 23 | void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; 24 | }; 25 | 26 | 27 | #endif 28 | 29 | /* Local Variables: */ 30 | /* mode: c++ */ 31 | /* End: */ 32 | -------------------------------------------------------------------------------- /networkprofiletablemodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include "networkprofiletablemodel.h" 10 | 11 | NetworkProfileTableModel::NetworkProfileTableModel(Config& config, QObject* parent) 12 | : QAbstractTableModel(parent), m_config(config) 13 | { 14 | } 15 | 16 | NetworkProfileTableModel::~NetworkProfileTableModel() 17 | { 18 | } 19 | 20 | int NetworkProfileTableModel::columnCount(const QModelIndex& parent) const 21 | { 22 | return parent.isValid() ? 0 : 3; 23 | } 24 | 25 | int NetworkProfileTableModel::rowCount(const QModelIndex& parent) const 26 | { 27 | return parent.isValid() ? 0 : static_cast(m_config.networks.size()); 28 | } 29 | 30 | QVariant NetworkProfileTableModel::data(const QModelIndex& index, int role) const 31 | { 32 | if ( !index.isValid() || ( role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::BackgroundRole )) 33 | return QVariant(); 34 | int row = index.row(); 35 | 36 | for ( const auto& n : m_config.networks ) 37 | { 38 | if ( row-- > 0 ) 39 | continue; 40 | 41 | if ( role == Qt::DisplayRole ) 42 | { 43 | switch (index.column()) 44 | { 45 | case 0: 46 | return QString::fromStdString(n.first); 47 | 48 | case 1: 49 | return QString::fromStdString(Config::networkProfileChoiceDisplayName(n.second.profile)); 50 | 51 | case 2: 52 | return QString::fromStdString(Config::interfaceTypeDisplayName(n.second.interfaceType)); 53 | } 54 | } 55 | else if ( role == Qt::EditRole ) 56 | { 57 | switch (index.column()) 58 | { 59 | case 1: 60 | return QVariant(static_cast(n.second.profile)); 61 | } 62 | } 63 | else if ( role == Qt::BackgroundRole ) 64 | { 65 | if ( n.second.interfaceActive == true ) 66 | return QVariant(QColor::fromRgb(222, 255, 222)); 67 | else 68 | return QVariant(); 69 | } 70 | } 71 | 72 | return QVariant(); 73 | } 74 | 75 | Qt::ItemFlags NetworkProfileTableModel::flags(const QModelIndex& index) const 76 | { 77 | if ( index.column() == 0 || index.column() == 2 ) return QAbstractTableModel::flags(index); 78 | return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; 79 | } 80 | 81 | 82 | bool NetworkProfileTableModel::setData(const QModelIndex &index, const QVariant &value, int role) 83 | { 84 | if ( !index.isValid() || role != Qt::EditRole || index.column() != 1 ) 85 | return false; 86 | 87 | int row = index.row(); 88 | 89 | for ( const auto& n : m_config.networks ) 90 | { 91 | if ( row-- > 0 ) 92 | continue; 93 | 94 | m_config.networks[n.first].profile = Config::NetworkProfileChoice(value.toInt()); 95 | emit dataChanged(index, index); 96 | return true; 97 | } 98 | return false; 99 | } 100 | 101 | void NetworkProfileTableModel::NPTMConfigChanged() 102 | { 103 | beginResetModel(); 104 | endResetModel(); 105 | } 106 | -------------------------------------------------------------------------------- /networkprofiletablemodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKPROFILETABLEMODEL_H 10 | #define NETWORKPROFILETABLEMODEL_H 11 | 12 | #include 13 | #include 14 | #include "configmanager.h" 15 | 16 | class NetworkProfileTableModel : public QAbstractTableModel 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | NetworkProfileTableModel(Config& config, QObject* parent = nullptr); 22 | virtual ~NetworkProfileTableModel(); 23 | 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; 25 | int columnCount(const QModelIndex& parent = QModelIndex()) const override; 26 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 27 | Qt::ItemFlags flags(const QModelIndex& index) const override; 28 | 29 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; 30 | 31 | void NPTMConfigChanged(); 32 | 33 | private: 34 | Config& m_config; 35 | }; 36 | 37 | #endif 38 | 39 | /* Local Variables: */ 40 | /* mode: c++ */ 41 | /* End: */ 42 | -------------------------------------------------------------------------------- /networkprofilewidget.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "networkprofilewidget.h" 16 | #include "serverdatadialog.h" 17 | 18 | NetworkProfileWidget::NetworkProfileWidget(ConfigMgr& configMgr, Config::NetworkProfile np, QWidget* parent) 19 | : QWidget(parent), 20 | ui(new Ui::NetworkProfileWidget), 21 | m_configMgr(configMgr), 22 | m_networkProfile(np) 23 | 24 | { 25 | ui->setupUi(this); 26 | 27 | m_serverTableModel = new ServersTableModel(m_configMgr.displayedConfig, m_networkProfile); 28 | ui->serverTable->setModel(m_serverTableModel); 29 | ui->serverTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 30 | ui->serverTable->hideColumn(5); 31 | connect(ui->serverTable, SIGNAL(clicked(const QModelIndex &)), this, SLOT(onTableClicked(const QModelIndex &))); 32 | connect(m_serverTableModel, &ServersTableModel::dataChanged, 33 | this, &NetworkProfileWidget::on_serverTableDataChanged); 34 | ui->editServerButton->setEnabled(false); 35 | ui->deleteServerButton->setVisible(false); 36 | ui->addServerButton->setVisible(false); 37 | ui->filterServersButton->setVisible(false); 38 | ui->validateData->setVisible(false); 39 | setNPWButtonStates(); 40 | 41 | ui->encryptAllTraffic->setToolTip("Always use encrypted connections (TLS) for all queries.\n Otherwise clear text (UCP/TCP) may also be used if the server does not support TLS."); 42 | ui->alwaysAuthenticate->setToolTip("Only use servers that can be authenticated using either\n a TLS authentication name or a Pin (SPKI Digest Value)"); 43 | ui->roundRobin->setToolTip("Open connections to all available servers and send queries in turn to each.\n Otherwise, use the first server only until a problem is encountered then move on to the next server and so on."); 44 | ui->editServerButton->setToolTip("Edit the properties of one of the servers (when that row is selected in the table)"); 45 | ui->revertButton->setToolTip("Revert to the default servers and profile settings built into Stubby Manager"); 46 | } 47 | 48 | NetworkProfileWidget::~NetworkProfileWidget() 49 | { 50 | delete ui; 51 | delete m_serverTableModel; 52 | } 53 | 54 | void NetworkProfileWidget::onTableClicked(const QModelIndex &index) { 55 | if (index.column() != 2) 56 | return; 57 | QVariant link = m_serverTableModel->data(index.siblingAtColumn(2), Qt::DisplayRole); 58 | QString url = "https://" + link.toString(); 59 | QDesktopServices::openUrl (QUrl(url)); 60 | } 61 | 62 | void NetworkProfileWidget::on_serverTable_clicked() { 63 | // Enable buttons if one and only one row is selected 64 | QItemSelectionModel *select = ui->serverTable->selectionModel(); 65 | QModelIndexList selection = select->selectedIndexes(); 66 | if (selection.count() == 0) { 67 | ui->editServerButton->setEnabled(false); 68 | return; 69 | } 70 | int count = 0, row; 71 | foreach (QModelIndex index, selection) { 72 | if (count == 0) { 73 | row = index.row(); 74 | count++; 75 | continue; 76 | } 77 | if (row != index.row()) { 78 | ui->editServerButton->setEnabled(false); 79 | return; 80 | } 81 | } 82 | ui->editServerButton->setEnabled(true); 83 | } 84 | 85 | void NetworkProfileWidget::on_editServerButton_clicked() { 86 | QItemSelectionModel *select = ui->serverTable->selectionModel(); 87 | QModelIndexList selection = select->selectedIndexes(); 88 | if (selection.count() == 0) 89 | return; 90 | int row = selection.begin()->row(); 91 | Config::Server& server = m_configMgr.displayedConfig.servers[row]; 92 | ServerDataDialog dialog(server, this); 93 | dialog.exec(); 94 | ui->editServerButton->setEnabled(false); 95 | setNPWGuiState(); 96 | } 97 | 98 | void NetworkProfileWidget::on_alwaysAuthenticate_stateChanged(int state) 99 | { 100 | m_configMgr.displayedConfig.profiles[m_networkProfile].alwaysAuthenticate = (state == Qt::CheckState::Checked); 101 | setNPWButtonStates(); 102 | } 103 | 104 | void NetworkProfileWidget::on_encryptAllTraffic_stateChanged(int state) 105 | { 106 | m_configMgr.displayedConfig.profiles[m_networkProfile].encryptAll = (state == Qt::CheckState::Checked); 107 | // If encryption is not enabled, authentication has no meaning 108 | ui->alwaysAuthenticate->setCheckState((Qt::CheckState)state); 109 | ui->alwaysAuthenticate->setEnabled(state == Qt::CheckState::Checked); 110 | setNPWButtonStates(); 111 | } 112 | 113 | void NetworkProfileWidget::on_roundRobin_stateChanged(int state) 114 | { 115 | m_configMgr.displayedConfig.profiles[m_networkProfile].roundRobin = (state == Qt::CheckState::Checked); 116 | setNPWButtonStates(); 117 | } 118 | 119 | void NetworkProfileWidget::on_validateData_stateChanged(int state) 120 | { 121 | m_configMgr.displayedConfig.profiles[m_networkProfile].validateData = (state == Qt::CheckState::Checked); 122 | setNPWButtonStates(); 123 | } 124 | 125 | void NetworkProfileWidget::on_applyButton_clicked() 126 | { 127 | m_configMgr.saveProfile(m_networkProfile); 128 | } 129 | 130 | void NetworkProfileWidget::on_discardButton_clicked() 131 | { 132 | m_configMgr.profileRestoreSaved(m_networkProfile); 133 | setNPWButtonStates(); 134 | m_serverTableModel->STPConfigChanged(); 135 | } 136 | 137 | void NetworkProfileWidget::on_revertButton_clicked() 138 | { 139 | m_configMgr.profileRestoreFactory(m_networkProfile); 140 | setNPWButtonStates(); 141 | m_serverTableModel->STPConfigChanged(); 142 | } 143 | 144 | void NetworkProfileWidget::on_serverTableDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) 145 | { 146 | setNPWButtonStates(); 147 | } 148 | 149 | void NetworkProfileWidget::setNPWGuiState() 150 | { 151 | ui->alwaysAuthenticate->setCheckState(m_configMgr.displayedConfig.profiles[m_networkProfile].alwaysAuthenticate ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); 152 | ui->encryptAllTraffic->setCheckState(m_configMgr.displayedConfig.profiles[m_networkProfile].encryptAll ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); 153 | ui->validateData->setCheckState(m_configMgr.displayedConfig.profiles[m_networkProfile].validateData ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); 154 | ui->roundRobin->setCheckState(m_configMgr.displayedConfig.profiles[m_networkProfile].roundRobin ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); 155 | 156 | m_serverTableModel->STPConfigChanged(); 157 | setNPWButtonStates(); 158 | } 159 | 160 | void NetworkProfileWidget::setNPWButtonStates() 161 | { 162 | bool unsaved = m_configMgr.profileModifiedFromSaved(m_networkProfile); 163 | bool notdefault = m_configMgr.profileModifiedFromFactory(m_networkProfile); 164 | 165 | ui->applyButton->setEnabled(unsaved); 166 | ui->discardButton->setEnabled(unsaved); 167 | ui->revertButton->setEnabled(notdefault); 168 | 169 | //if (unsaved) 170 | emit userProfileEditInProgress(); 171 | } 172 | -------------------------------------------------------------------------------- /networkprofilewidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKPROFILE_H 10 | #define NETWORKPROFILE_H 11 | 12 | #include 13 | #include 14 | 15 | #include "configmanager.h" 16 | #include "serverstablemodel.h" 17 | #include "ui_networkprofilewidget.h" 18 | 19 | QT_BEGIN_NAMESPACE 20 | namespace Ui { class NetworkProfileWidget; } 21 | QT_END_NAMESPACE 22 | 23 | class NetworkProfileWidget : public QWidget 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit NetworkProfileWidget(ConfigMgr& configMsg, Config::NetworkProfile np, QWidget* parent = nullptr); 29 | virtual ~NetworkProfileWidget(); 30 | 31 | void setNPWGuiState(); 32 | 33 | signals: 34 | void userProfileEditInProgress(); 35 | 36 | public slots: 37 | void on_alwaysAuthenticate_stateChanged(int state); 38 | void on_encryptAllTraffic_stateChanged(int state); 39 | void on_roundRobin_stateChanged(int state); 40 | void on_validateData_stateChanged(int state); 41 | 42 | void on_applyButton_clicked(); 43 | void on_discardButton_clicked(); 44 | void on_revertButton_clicked(); 45 | void on_serverTable_clicked(); 46 | void on_editServerButton_clicked(); 47 | 48 | void on_serverTableDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); 49 | void onTableClicked(const QModelIndex &index); 50 | private: 51 | void setNPWButtonStates(); 52 | 53 | Ui::NetworkProfileWidget* ui; 54 | 55 | ConfigMgr& m_configMgr; 56 | Config::NetworkProfile m_networkProfile; 57 | ServersTableModel* m_serverTableModel; 58 | }; 59 | 60 | #endif 61 | 62 | /* Local Variables: */ 63 | /* mode: c++ */ 64 | /* End: */ 65 | -------------------------------------------------------------------------------- /networkprofilewidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NetworkProfileWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 531 10 | 410 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Network type settings 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | QLayout::SetDefaultConstraint 29 | 30 | 31 | 32 | 33 | 34 | 35 | Encrypt all traffic 36 | 37 | 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | Always Authenticate 46 | 47 | 48 | true 49 | 50 | 51 | 52 | 53 | 54 | 55 | Validate data 56 | 57 | 58 | 59 | 60 | 61 | 62 | Round robin 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 10 72 | 73 | 74 | 75 | 76 | Qt::Horizontal 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | DNS Servers 86 | 87 | 88 | 89 | 90 | 91 | 92 | Qt::Horizontal 93 | 94 | 95 | 96 | 40 97 | 20 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | false 106 | 107 | 108 | Filter 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | true 120 | 121 | 122 | Edit 123 | 124 | 125 | 126 | 127 | 128 | 129 | false 130 | 131 | 132 | Add 133 | 134 | 135 | 136 | 137 | 138 | 139 | false 140 | 141 | 142 | Delete 143 | 144 | 145 | 146 | 147 | 148 | 149 | Qt::Horizontal 150 | 151 | 152 | 153 | 40 154 | 20 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | false 163 | 164 | 165 | 166 | Exclude network provided servers 167 | 168 | 169 | 170 | 171 | Include network provided servers 172 | 173 | 174 | 175 | 176 | Use only network provided servers 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 6 194 | 195 | 196 | 197 | 198 | Qt::Horizontal 199 | 200 | 201 | 202 | 40 203 | 20 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | Revert to Defaults 212 | 213 | 214 | 215 | 216 | 217 | 218 | Discard Edits 219 | 220 | 221 | 222 | 223 | 224 | 225 | Apply 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /networkswidget.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include "config.h" 12 | #include "networkprofiledelegate.h" 13 | #include "networkswidget.h" 14 | #include "networkswidgetfilterproxymodel.h" 15 | #include "mainwindow.h" 16 | 17 | NetworksWidget::NetworksWidget(ConfigMgr& configMgr, MainWindow* main, QWidget* parent) 18 | : QWidget(parent), 19 | ui(new Ui::NetworkList), 20 | m_configMgr(configMgr), 21 | m_mainWindow(main) 22 | 23 | { 24 | ui->setupUi(this); 25 | 26 | ui->defaultProfile->addItem(QString::fromStdString(Config::networkProfileDisplayName(Config::NetworkProfile::trusted)), QVariant(static_cast(Config::NetworkProfile::trusted))); 27 | ui->defaultProfile->addItem(QString::fromStdString(Config::networkProfileDisplayName(Config::NetworkProfile::untrusted)), QVariant(static_cast(Config::NetworkProfile::untrusted))); 28 | ui->defaultProfile->addItem(QString::fromStdString(Config::networkProfileDisplayName(Config::NetworkProfile::hostile)), QVariant(static_cast(Config::NetworkProfile::hostile))); 29 | 30 | m_networkTableModel = new NetworkProfileTableModel(m_configMgr.displayedConfig); 31 | 32 | m_wifiModel = new NetworksWidgetFilterProxyModel(this, "WiFi"); 33 | m_wifiModel->setSourceModel(m_networkTableModel); 34 | m_wiredModel = new NetworksWidgetFilterProxyModel(this, "Ethernet"); 35 | m_wiredModel->setSourceModel(m_networkTableModel); 36 | 37 | ui->networkTable->setModel(m_wifiModel); 38 | ui->networkTable->hideColumn(2); 39 | ui->networkTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 40 | ui->networkTable->setSelectionBehavior(QAbstractItemView::SelectRows); 41 | ui->networkTable->setSelectionMode(QAbstractItemView::ExtendedSelection); 42 | ui->networkTable->setItemDelegateForColumn(1, new NetworkProfileDelegate(ui->networkTable)); 43 | ui->networkTable->setSortingEnabled(true); 44 | m_selectionWifiModel = ui->networkTable->selectionModel(); 45 | 46 | ui->networkWiredTable->setModel(m_wiredModel); 47 | ui->networkWiredTable->hideColumn(2); 48 | ui->networkWiredTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 49 | ui->networkWiredTable->setSelectionBehavior(QAbstractItemView::SelectRows); 50 | ui->networkWiredTable->setSelectionMode(QAbstractItemView::ExtendedSelection); 51 | ui->networkWiredTable->setItemDelegateForColumn(1, new NetworkProfileDelegate(ui->networkWiredTable)); 52 | ui->networkWiredTable->setSortingEnabled(true); 53 | m_selectionWiredModel = ui->networkWiredTable->selectionModel(); 54 | 55 | bool sel=m_selectionWifiModel->hasSelection(); 56 | ui->forgetButton->setEnabled(sel); 57 | 58 | ui->forgetButton->setToolTip("Remove an inactive WiFi network from the configuration.\n Active networks cannot be removed."); 59 | ui->defaultProfile->setToolTip("Set a profile to be used automatically whenever new networks are joined"); 60 | 61 | connect(m_networkTableModel, &NetworkProfileTableModel::dataChanged, 62 | this, &NetworksWidget::on_networkTableDataChanged); 63 | connect(m_selectionWifiModel, &QItemSelectionModel::selectionChanged, 64 | this, &NetworksWidget::on_networkTableSelectionChanged); 65 | // connect(m_selectionWiredModel, &QItemSelectionModel::selectionChanged, 66 | // this, &NetworksWidget::on_networkTableSelectionChanged); 67 | connect(m_networkTableModel, &NetworkProfileTableModel::modelReset, 68 | this, &NetworksWidget::PersistentEdit); 69 | 70 | } 71 | 72 | NetworksWidget::~NetworksWidget() 73 | { 74 | delete ui; 75 | delete m_networkTableModel; 76 | } 77 | 78 | void NetworksWidget::PersistentEdit() 79 | { 80 | for (int i=0; irowCount(); ++i) 81 | ui->networkTable->openPersistentEditor(m_wifiModel->index(i, 1)); 82 | for (int i=0; irowCount(); ++i) 83 | ui->networkWiredTable->openPersistentEditor(m_wiredModel->index(i, 1)); 84 | } 85 | 86 | void NetworksWidget::on_applyButton_clicked() 87 | { 88 | m_configMgr.saveNetworks(); 89 | } 90 | 91 | void NetworksWidget::on_discardButton_clicked() 92 | { 93 | // Only affects displayed config (so local) 94 | m_configMgr.networksRestoreSaved(); 95 | setNWGuiState(); 96 | } 97 | 98 | void NetworksWidget::on_defaultProfile_activated(int /*index*/) { 99 | m_configMgr.displayedConfig.defaultNetworkProfile = Config::networkProfileFromYamlKey(ui->defaultProfile->currentText().toLower().toUtf8().constData()); 100 | setNWButtonStates(); 101 | } 102 | 103 | void NetworksWidget::on_networkTableDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) 104 | { 105 | setNWButtonStates(); 106 | } 107 | 108 | void NetworksWidget::setNWGuiState() 109 | { 110 | ui->defaultProfile->setCurrentText(QString::fromStdString(Config::networkProfileDisplayName(m_configMgr.displayedConfig.defaultNetworkProfile))); 111 | setNWButtonStates(); 112 | m_networkTableModel->NPTMConfigChanged(); 113 | } 114 | 115 | void NetworksWidget::setNWButtonStates() 116 | { 117 | bool unsaved = m_configMgr.networksModifiedFromSaved(); 118 | 119 | ui->applyButton->setEnabled(unsaved); 120 | ui->discardButton->setEnabled(unsaved); 121 | bool sel=m_selectionWifiModel->hasSelection(); 122 | ui->forgetButton->setEnabled(sel); 123 | 124 | if (unsaved) 125 | emit userNetworksEditInProgress(); 126 | } 127 | 128 | void NetworksWidget::on_forgetButton_clicked() 129 | { 130 | auto& networks = m_configMgr.displayedConfig.networks; 131 | 132 | for ( const auto& row : m_selectionWifiModel->selectedRows() ) 133 | { 134 | std::string name = m_wifiModel->data(row).toString().toStdString(); 135 | if (m_wifiModel->data(row, Qt::BackgroundRole).value() == QColor::fromRgb(222, 255, 222)) { 136 | QString message = "Ignoring 'Forget' for active Wifi network "; 137 | message.append(name.c_str()); 138 | m_mainWindow->systrayMsg(message); 139 | message.prepend("Status: "); 140 | m_mainWindow->statusMsg(message); 141 | continue; 142 | } 143 | networks.erase(networks.find(name)); 144 | qInfo("Forgetting wireless network %s", name.c_str()); 145 | } 146 | // for ( const auto& row : m_selectionWiredModel->selectedRows() ) 147 | // { 148 | // std::string name = m_wiredModel->data(row).toString().toStdString(); 149 | // if (m_wiredModel->data(row, Qt::BackgroundRole).value() == QColor::fromRgb(222, 255, 222)) { 150 | // qInfo("Ignoring active network %s ", name.c_str()); 151 | // continue; 152 | // } 153 | // networks.erase(networks.find(name)); 154 | // qInfo("Forgetting wired network %s", name.c_str()); 155 | // } 156 | // m_selectionWiredModel->reset(); 157 | m_selectionWifiModel->reset(); 158 | 159 | setNWButtonStates(); 160 | m_networkTableModel->NPTMConfigChanged(); 161 | } 162 | 163 | void NetworksWidget::on_networkTableSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) 164 | { 165 | ui->forgetButton->setEnabled(!selected.empty()); 166 | } 167 | -------------------------------------------------------------------------------- /networkswidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKS_H 10 | #define NETWORKS_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "configmanager.h" 17 | #include "networkprofiletablemodel.h" 18 | #include "ui_networkswidget.h" 19 | 20 | QT_BEGIN_NAMESPACE 21 | namespace Ui { class NetworkList; } 22 | QT_END_NAMESPACE 23 | 24 | class NetworksWidget : public QWidget 25 | { 26 | Q_OBJECT 27 | 28 | public: 29 | explicit NetworksWidget(ConfigMgr& configMgr, MainWindow* main, QWidget* parent = nullptr); 30 | virtual ~NetworksWidget(); 31 | 32 | void setNWGuiState(); 33 | 34 | signals: 35 | void userNetworksEditInProgress(); 36 | 37 | public slots: 38 | void on_applyButton_clicked(); 39 | void on_discardButton_clicked(); 40 | void on_forgetButton_clicked(); 41 | void on_defaultProfile_activated(int index); 42 | 43 | void on_networkTableDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); 44 | void on_networkTableSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); 45 | void PersistentEdit(); 46 | 47 | private: 48 | void setNWButtonStates(); 49 | 50 | Ui::NetworkList* ui; 51 | 52 | ConfigMgr& m_configMgr; 53 | MainWindow* m_mainWindow; 54 | NetworkProfileTableModel* m_networkTableModel; 55 | QSortFilterProxyModel* m_wifiModel; 56 | QSortFilterProxyModel* m_wiredModel; 57 | QItemSelectionModel* m_selectionWifiModel; 58 | QItemSelectionModel* m_selectionWiredModel; 59 | }; 60 | 61 | 62 | #endif 63 | 64 | /* Local Variables: */ 65 | /* mode: c++ */ 66 | /* End: */ 67 | -------------------------------------------------------------------------------- /networkswidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NetworkList 4 | 5 | 6 | 7 | 0 8 | 0 9 | 528 10 | 426 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 6 30 | 31 | 32 | 33 | 34 | Default profile 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Qt::Horizontal 45 | 46 | 47 | 48 | 40 49 | 20 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | true 58 | 59 | 60 | Forget WiFi Network 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Qt::Vertical 70 | 71 | 72 | 73 | 74 | 0 75 | 2 76 | 77 | 78 | 79 | 80 | 81 | true 82 | 83 | 84 | 85 | 0 86 | 5 87 | 88 | 89 | 90 | QAbstractScrollArea::AdjustIgnored 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 6 99 | 100 | 101 | 102 | 103 | Qt::Horizontal 104 | 105 | 106 | 107 | 40 108 | 20 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Discard Edits 117 | 118 | 119 | 120 | 121 | 122 | 123 | Apply 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /networkswidgetfilterproxymodel.cpp: -------------------------------------------------------------------------------- 1 | #include "networkswidgetfilterproxymodel.h" 2 | #include "networkprofiletablemodel.h" 3 | 4 | NetworksWidgetFilterProxyModel::NetworksWidgetFilterProxyModel(QObject *parent, QString view): QSortFilterProxyModel(parent), m_view(view) {} 5 | 6 | bool NetworksWidgetFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { 7 | QModelIndex index = sourceModel()->index(sourceRow, 2, sourceParent); 8 | return(sourceModel()->data(index).toString().contains(m_view)); 9 | } 10 | 11 | QVariant NetworksWidgetFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const 12 | { 13 | if ( role != Qt::DisplayRole || orientation != Qt::Horizontal ) 14 | return QVariant(); 15 | 16 | if ( m_view == "Ethernet" ) { 17 | switch (section) 18 | { 19 | case 0: return tr("Wired Networks"); 20 | case 1: return tr("Profile"); 21 | } 22 | } else if (m_view == "WiFi") { 23 | switch (section) 24 | { 25 | case 0: return tr("WiFi Networks"); 26 | case 1: return tr("Profile"); 27 | } 28 | } 29 | return QVariant(); 30 | } 31 | 32 | 33 | bool NetworksWidgetFilterProxyModel::lessThan(const QModelIndex &left, 34 | const QModelIndex &right) const { 35 | QVariant leftData = sourceModel()->data(left); 36 | QVariant rightData = sourceModel()->data(right); 37 | QColor leftColour = sourceModel()->data(left, Qt::BackgroundRole).value(); 38 | QColor rightColour = sourceModel()->data(right, Qt::BackgroundRole).value(); 39 | 40 | if (leftColour != rightColour) { 41 | if (leftColour == QColor::fromRgb(222, 255, 222)) 42 | return false; 43 | else 44 | return true; 45 | } 46 | else if (leftData.userType() == QMetaType::QString) 47 | return QString::localeAwareCompare(leftData.toString(), rightData.toString()) > 0; 48 | else 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /networkswidgetfilterproxymodel.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORKLISTFILTERPROXYMODEL_H 2 | #define NETWORKLISTFILTERPROXYMODEL_H 3 | 4 | #include 5 | 6 | class NetworksWidgetFilterProxyModel : public QSortFilterProxyModel 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit NetworksWidgetFilterProxyModel(QObject *parent = nullptr, QString view = ""); 11 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; 12 | QVariant headerData(int section, Qt::Orientation orientation, int role) const override; 13 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const; 14 | 15 | private: 16 | QString m_view; 17 | }; 18 | 19 | #endif // NETWORKLISTFILTERPROXYMODEL_H 20 | -------------------------------------------------------------------------------- /os/linux/configmanager_linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "configmanager_linux.h" 17 | #include "mainwindow.h" 18 | 19 | // TDOD: Set this module to look for default stuff in /etc/StubbyGUI 20 | static const char STUBBY_GUI_CONF_DIR[] = "/tmp"; 21 | 22 | ConfigMgrLinux::ConfigMgrLinux(MainWindow *parent) 23 | : ConfigMgr(parent) 24 | { 25 | } 26 | 27 | ConfigMgrLinux::~ConfigMgrLinux() 28 | { 29 | } 30 | 31 | 32 | std::string ConfigMgrLinux::defaultConfigDir() 33 | { 34 | return STUBBY_GUI_CONF_DIR; 35 | } 36 | 37 | std::string ConfigMgrLinux::factoryConfigDir() 38 | { 39 | return STUBBY_GUI_CONF_DIR; 40 | } 41 | 42 | ConfigMgr *ConfigMgr::factory(MainWindow *parent) 43 | { 44 | return new ConfigMgrLinux(parent); 45 | } 46 | -------------------------------------------------------------------------------- /os/linux/configmanager_linux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef CONFIGMGRLINUX_H 10 | #define CONFIGMGRLINUX_H 11 | 12 | #include 13 | 14 | #include "configmanager.h" 15 | 16 | class ConfigMgrLinux : public ConfigMgr 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | ConfigMgrLinux(MainWindow *parent); 22 | virtual ~ConfigMgrLinux(); 23 | 24 | protected: 25 | virtual std::string appDataDir(); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /os/linux/logmanager_linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include "logmanager_linux.h" 10 | #include "mainwindow.h" 11 | 12 | #include 13 | #include 14 | 15 | LogMgrLinux::LogMgrLinux(MainWindow *parent) : 16 | QObject(parent) 17 | { 18 | } 19 | 20 | LogMgrLinux::~LogMgrLinux() 21 | { 22 | } 23 | 24 | void LogMgrLinux::start() 25 | { 26 | } 27 | 28 | void LogMgrLinux::stop() 29 | { 30 | } 31 | 32 | ILogMgr *ILogMgr::factory(MainWindow *parent) 33 | { 34 | return new LogMgrLinux(parent); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /os/linux/logmanager_linux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef LOGMANAGERLINUX_H 10 | #define LOGMANAGERLINUX_H 11 | 12 | #include 13 | 14 | #include "logmanager.h" 15 | 16 | class LogMgrLinux : public QObject, public ILogMgr 17 | { 18 | Q_OBJECT 19 | 20 | Q_INTERFACES(ILogMgr) 21 | 22 | public: 23 | LogMgrLinux(MainWindow *parent = 0); 24 | ~LogMgrLinux(); 25 | 26 | void start(); 27 | void stop(); 28 | 29 | signals: 30 | void alert(bool on); 31 | }; 32 | 33 | #endif // LOGMANAGERLINUX_H 34 | -------------------------------------------------------------------------------- /os/linux/networkmanager_linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "mainwindow.h" 13 | #include "networkmanager_linux.h" 14 | 15 | 16 | NetworkMgrLinux::NetworkMgrLinux(MainWindow *parent) : 17 | NetworkMgr(parent) 18 | { 19 | } 20 | 21 | NetworkMgrLinux::~NetworkMgrLinux() 22 | { 23 | } 24 | 25 | int NetworkMgrLinux::setLocalhostDNS() 26 | { 27 | return 1; 28 | } 29 | 30 | int NetworkMgrLinux::unsetLocalhostDNS() 31 | { 32 | return 1; 33 | } 34 | 35 | int NetworkMgrLinux::getStateDNS() 36 | { 37 | return 1; 38 | } 39 | 40 | int NetworkMgrLinux::testQuery() 41 | { 42 | return 1; 43 | } 44 | 45 | std::vector NetworkMgrLinux::getNetworks() 46 | { 47 | std::vector res; 48 | res.push_back("eth0"); 49 | return res; 50 | } 51 | 52 | NetworkMgr *NetworkMgr::factory(MainWindow *parent) { 53 | return new NetworkMgrLinux(parent); 54 | } 55 | -------------------------------------------------------------------------------- /os/linux/networkmanager_linux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKMGRLINUX_H 10 | #define NETWORKMGRLINUX_H 11 | 12 | #include 13 | #include 14 | 15 | #include "networkmanager.h" 16 | 17 | class NetworkMgrLinux : public NetworkMgr 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | NetworkMgrLinux(MainWindow *parent = 0); 23 | virtual ~NetworkMgrLinux(); 24 | 25 | protected: 26 | int setLocalhostDNS(); 27 | int unsetLocalhostDNS(); 28 | int getStateDNS(); 29 | int testQuery(); 30 | std::vector getNetworks(); 31 | }; 32 | 33 | #endif // NETWORKMGRLINUX_H 34 | -------------------------------------------------------------------------------- /os/linux/servicemanager_linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "mainwindow.h" 13 | #include "servicemanager_linux.h" 14 | 15 | 16 | ServiceMgrLinux::ServiceMgrLinux(MainWindow *parent) : 17 | ServiceMgr(parent) 18 | { 19 | qInfo("Creating Linux service mgr"); 20 | } 21 | 22 | ServiceMgrLinux::~ServiceMgrLinux() 23 | { 24 | } 25 | 26 | int ServiceMgrLinux::getStateofService() 27 | { 28 | qInfo("getting service state"); 29 | return 1; 30 | } 31 | 32 | int ServiceMgrLinux::startService(QString configfile, int loglevel) 33 | { 34 | qInfo("start service"); 35 | 36 | return 1; 37 | } 38 | 39 | int ServiceMgrLinux::stopService() 40 | { 41 | qInfo("stop service"); 42 | 43 | return 1; 44 | } 45 | 46 | int ServiceMgrLinux::restartService() 47 | { 48 | stopService(); 49 | return startService(); 50 | } 51 | 52 | ServiceMgr *ServiceMgr::factory(MainWindow *parent) 53 | { 54 | return new ServiceMgrLinux(parent); 55 | } 56 | -------------------------------------------------------------------------------- /os/linux/servicemanager_linux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef SERVICEMGRLINUX_H 10 | #define SERVICEMGRLINUX_H 11 | 12 | #include 13 | 14 | #include "servicemanager.h" 15 | 16 | class MainWindow; 17 | 18 | 19 | class ServiceMgrLinux : public ServiceMgr 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | ServiceMgrLinux(MainWindow *parent); 25 | virtual ~ServiceMgrLinux(); 26 | 27 | private: 28 | int getStateofService(); 29 | int startService(QString configfile = "", int loglevel = 6); 30 | int stopService(); 31 | int restartService(); 32 | }; 33 | 34 | #endif // SERVICEMGRLINUX_H 35 | -------------------------------------------------------------------------------- /os/macos/configmanager_macos.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "configmanager_macos.h" 17 | #include "mainwindow.h" 18 | 19 | static const char STUBBY_GUI_CONF_DIR[] = "/Applications/StubbyManager.app/Contents/MacOS/StubbyGUI"; 20 | 21 | ConfigMgrMacOS::ConfigMgrMacOS(MainWindow *parent) 22 | : ConfigMgr(parent) 23 | { 24 | } 25 | 26 | ConfigMgrMacOS::~ConfigMgrMacOS() 27 | { 28 | } 29 | 30 | std::string ConfigMgrMacOS::appDataDir() 31 | { 32 | return STUBBY_GUI_CONF_DIR; 33 | } 34 | 35 | ConfigMgr *ConfigMgr::factory(MainWindow *parent) 36 | { 37 | return new ConfigMgrMacOS(parent); 38 | } 39 | -------------------------------------------------------------------------------- /os/macos/configmanager_macos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef CONFIGMGRMACOS_H 10 | #define CONFIGMGRMACOS_H 11 | 12 | #include 13 | 14 | #include "configmanager.h" 15 | 16 | class ConfigMgrMacOS : public ConfigMgr 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | ConfigMgrMacOS(MainWindow *parent); 22 | virtual ~ConfigMgrMacOS(); 23 | 24 | protected: 25 | virtual std::string appDataDir(); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /os/macos/logmanager_macos.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include "logmanager_macos.h" 10 | #include "mainwindow.h" 11 | 12 | #include 13 | #include 14 | 15 | LogMgrMacOS::LogMgrMacOS(MainWindow *parent) : 16 | QObject(parent), 17 | m_mainWindow(parent), 18 | m_logger(0), 19 | m_isRunning(false) 20 | { 21 | m_logger = new RunTaskMacos("tail -f /var/log/stubby.log", this); 22 | connect(m_logger, SIGNAL(started()), this, SLOT(on_started())); 23 | connect(m_logger, SIGNAL(finished(int)), this, SLOT(on_finished(int))); 24 | connect(m_logger, SIGNAL(readyReadStandardOutput()), this, SLOT(on_readyRead())); 25 | } 26 | 27 | LogMgrMacOS::~LogMgrMacOS() 28 | { 29 | } 30 | 31 | void LogMgrMacOS::start() 32 | { 33 | m_logger->start(); 34 | } 35 | 36 | void LogMgrMacOS::stop() 37 | { 38 | m_logger->terminate(); 39 | } 40 | 41 | void LogMgrMacOS::on_started() 42 | { 43 | m_isRunning = true; 44 | } 45 | 46 | void LogMgrMacOS::on_finished(int /*exitCode*/) 47 | { 48 | m_isRunning = false; 49 | } 50 | 51 | void LogMgrMacOS::on_readyRead() 52 | { 53 | QByteArray stdoutData; 54 | stdoutData = m_logger->readAllStandardOutput(); 55 | 56 | //static bool isAlert = false; 57 | static QByteArray incompleteLine; 58 | incompleteLine.append(stdoutData); 59 | QList lines = incompleteLine.split('\n'); 60 | int n = lines.count(); 61 | 62 | /*for (int i = 0; i < n-1; i++) {; 63 | // now parse this line of data - for now just look for indication of failure or success 64 | if (lines[i].contains("*FAILURE* no valid transports or upstreams available!")) { 65 | if (!isAlert) emit alert(true); 66 | isAlert = true; 67 | } 68 | // TODO: This won't mean a successfull connection, just a retry. 69 | // There's no text that works for Strict and Oppo at the moment..... 70 | if (lines[i].contains("Conn opened: ")) { 71 | if (isAlert) emit alert(false); 72 | isAlert = false; 73 | } 74 | }*/ 75 | incompleteLine = lines[n-1]; //save the remnant so it can be processed next time 76 | 77 | m_mainWindow->logMsg(QString::fromLatin1(stdoutData.data())); 78 | 79 | } 80 | 81 | ILogMgr *ILogMgr::factory(MainWindow *parent) 82 | { 83 | return new LogMgrMacOS(parent); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /os/macos/logmanager_macos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef LOGMANAGERMACOS_H 10 | #define LOGMANAGERMACOS_H 11 | 12 | #include 13 | 14 | #include "logmanager.h" 15 | #include "runtask_macos.h" 16 | 17 | 18 | class LogMgrMacOS : public QObject, public ILogMgr 19 | { 20 | Q_OBJECT 21 | 22 | Q_INTERFACES(ILogMgr) 23 | 24 | public: 25 | LogMgrMacOS(MainWindow *parent = 0); 26 | ~LogMgrMacOS(); 27 | 28 | void start(); 29 | void stop(); 30 | 31 | signals: 32 | void alert(bool on); 33 | 34 | protected: 35 | MainWindow *m_mainWindow; 36 | 37 | private slots: 38 | void on_started(); 39 | void on_finished(int exitCode); 40 | void on_readyRead(); 41 | 42 | private: 43 | RunTaskMacos *m_logger; 44 | bool m_isRunning; 45 | }; 46 | 47 | #endif // LOGMANAGERMACOS_H 48 | -------------------------------------------------------------------------------- /os/macos/networkmanager_macos.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "mainwindow.h" 13 | #include "networkmanager_macos.h" 14 | 15 | 16 | NetworkMgrMacos::NetworkMgrMacos(MainWindow *parent) : 17 | NetworkMgr(parent), 18 | m_setLocalhost(0), 19 | m_unsetLocalhost(0), 20 | m_getNetworkState(0), 21 | m_testQuery(0) 22 | { 23 | m_setLocalhost = new RunHelperTaskMacos("dns_stubby", RunHelperTaskMacos::RIGHT_DNS_LOCAL, QString(), this, parent); 24 | connect(m_setLocalhost, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_setLocalhost_finished(int,QProcess::ExitStatus))); 25 | 26 | m_unsetLocalhost = new RunHelperTaskMacos("dns_default", RunHelperTaskMacos::RIGHT_DNS_LOCAL, QString(), this, parent); 27 | connect(m_unsetLocalhost, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_unsetLocalhost_finished(int, QProcess::ExitStatus))); 28 | 29 | m_getNetworkState = new RunHelperTaskMacos("dns_list", QString(), QString(), this, parent); 30 | connect(m_getNetworkState, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_getNetworkState_finished(int, QProcess::ExitStatus))); 31 | connect(m_getNetworkState, SIGNAL(readyReadStandardOutput()), this, SLOT(on_getNetworkState_readyReadStdout())); 32 | 33 | m_getActiveNetworks = new RunHelperTaskMacos("dns_get_active_networks", QString(), QString(), this, parent); 34 | m_getSSID = new RunHelperTaskMacos("dns_get_wifi_ssid", QString(), QString(), this, parent); 35 | 36 | m_testQuery = new RunTaskMacos("dig @127.0.0.1 getdnsapi.net", this); 37 | connect(m_testQuery, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_testQuery_finished(int, QProcess::ExitStatus))); 38 | } 39 | 40 | NetworkMgrMacos::~NetworkMgrMacos() 41 | { 42 | } 43 | 44 | int NetworkMgrMacos::setLocalhostDNS() 45 | { 46 | m_setLocalhost->start(); 47 | return 0; 48 | } 49 | 50 | int NetworkMgrMacos::unsetLocalhostDNS() 51 | { 52 | m_unsetLocalhost->start(); 53 | return 0; 54 | } 55 | 56 | int NetworkMgrMacos::getStateDNS(bool reportNoChange) 57 | { 58 | m_getNetworkState_output = ""; 59 | m_getNetworkState->start(); 60 | return 0; 61 | } 62 | 63 | int NetworkMgrMacos::testQuery() { 64 | m_testQuery->start(); 65 | return 0; 66 | } 67 | 68 | void NetworkMgrMacos::on_testQuery_finished(int, QProcess::ExitStatus) 69 | { 70 | QByteArray stdoutData; 71 | stdoutData = m_testQuery->readAllStandardOutput(); 72 | if (stdoutData.isEmpty()) { 73 | emit testQueryResult(false); 74 | return; 75 | } 76 | if (stdoutData.contains("NOERROR")) { 77 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "OK"; 78 | emit testQueryResult(true); 79 | } 80 | else { 81 | emit testQueryResult(false); 82 | } 83 | } 84 | 85 | void NetworkMgrMacos::on_setLocalhost_finished(int exitCode, QProcess::ExitStatus) 86 | { 87 | qDebug("SetLocalhost exit code is %d", exitCode); 88 | getState(false); 89 | } 90 | 91 | void NetworkMgrMacos::on_unsetLocalhost_finished(int exitCode, QProcess::ExitStatus) 92 | { 93 | qDebug("UnsetLocalhost exit code is %d", exitCode); 94 | getState(false); 95 | } 96 | 97 | void NetworkMgrMacos::on_getNetworkState_finished(int exitCode, QProcess::ExitStatus exitStatus) 98 | { 99 | qDebug("getState exit code is %d", exitCode); 100 | /* 101 | * $ sudo ./stubby-setdns.sh -l 102 | * ** Current DNS settings ** 103 | * Apple USB Ethernet Adapter: 127.0.0.1 ::1 104 | * Wi-Fi: 127.0.0.1 ::1 105 | * Bluetooth PAN: 127.0.0.1 ::1 106 | * $ sudo ./stubby-setdns.sh 107 | * ** Current DNS settings ** -l 108 | * Apple USB Ethernet Adapter: There aren't any DNS Servers set on Apple USB Ethernet Adapter. 109 | * Wi-Fi: There aren't any DNS Servers set on Wi-Fi. 110 | * Bluetooth PAN: There aren't any DNS Servers set on Bluetooth PAN. 111 | * $ 112 | */ 113 | 114 | if (exitStatus == QProcess::NormalExit) { 115 | QStringList slist = m_getNetworkState_output.split("\n"); 116 | qDebug("Output from stdout is\n%s", m_getNetworkState_output.toLatin1().data()); 117 | int numberOfConnectors = slist.length() - 2; 118 | bool isLocalhost[numberOfConnectors]; 119 | bool isNotLocalhost[numberOfConnectors]; 120 | 121 | QString localPID("127.0.0.1 ::1"); 122 | int i = 1; 123 | while (i <= numberOfConnectors) { 124 | if (slist[i].contains(&localPID)) { 125 | isLocalhost[i-1] = true; 126 | isNotLocalhost[i-1] = false; 127 | } else { 128 | isLocalhost[i-1] = false; 129 | isNotLocalhost[i-1] = true; 130 | } 131 | i++; 132 | } 133 | 134 | /* if all are set to Localhost then stubby DNS is place */ 135 | i = 0; 136 | while ((i < numberOfConnectors) && isLocalhost[i]) { i++; } 137 | if (i==numberOfConnectors) { 138 | m_networkState = Localhost; 139 | m_mainwindow->statusMsg("Status: DNS settings using localhost."); 140 | emit networkStateChanged(Localhost); 141 | qDebug("All connections are using Localhost"); 142 | return; 143 | } 144 | 145 | /* if all none are Localhost then something else is being used */ 146 | i = 0; 147 | while ((i < numberOfConnectors) && isNotLocalhost[i]) { i++; } 148 | if (i==numberOfConnectors) { 149 | m_mainwindow->statusMsg("Status: DNS settings using default system settings."); 150 | m_networkState = NotLocalhost; 151 | emit networkStateChanged(NotLocalhost); 152 | qDebug("No connections are using Localhost"); 153 | return; 154 | } 155 | 156 | /* otherwhise, the true state is unknown.*/ 157 | } 158 | m_networkState = Unknown; 159 | m_mainwindow->statusMsg("Error - DNS server use of localhost is not clear"); 160 | emit networkStateChanged(Unknown); 161 | qDebug("Error - DNS server use of localhost is not clear"); 162 | } 163 | 164 | void NetworkMgrMacos::on_getNetworkState_readyReadStdout() 165 | 166 | { 167 | m_getNetworkState_output = m_getNetworkState_output + QString::fromLatin1(m_getNetworkState->readAllStandardOutput().data()); 168 | } 169 | 170 | std::vector NetworkMgrMacos::getNetworks() { 171 | std::vector res; 172 | 173 | m_getActiveNetworks->start(); 174 | if (!m_getActiveNetworks->waitForStarted()) 175 | res.push_back("Process didn't start"); 176 | // TODO: This is blocking.... change interface so it uses a callback 177 | // TODO: deal with multiple networks 178 | m_getActiveNetworks->waitForReadyRead(); 179 | QString result = QString::fromLatin1(m_getActiveNetworks->readAll().data()); 180 | if (result == "Wi-Fi\n") { 181 | m_getSSID->start(); 182 | if (!m_getSSID->waitForStarted()) 183 | res.push_back("Process didn't start"); 184 | // TODO: This is blocking.... change interface so it uses a callback 185 | m_getSSID->waitForReadyRead(); 186 | QString ssid = QString::fromLatin1(m_getSSID->readAll().data()); 187 | ssid.chop(1); 188 | if (ssid.isEmpty()) 189 | ssid = "Not connected"; 190 | res.push_back("Wi-Fi (" + ssid.toStdString() + ")"); 191 | } 192 | return res; 193 | } 194 | 195 | NetworkMgr *NetworkMgr::factory(MainWindow *parent) { 196 | return new NetworkMgrMacos(parent); 197 | } 198 | -------------------------------------------------------------------------------- /os/macos/networkmanager_macos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKMGRMACOS_H 10 | #define NETWORKMGRMACOS_H 11 | 12 | #include 13 | #include 14 | 15 | #include "networkmanager.h" 16 | #include "os/macos/runtask_macos.h" 17 | 18 | 19 | class NetworkMgrMacos : public NetworkMgr 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | NetworkMgrMacos(MainWindow *parent = 0); 25 | virtual ~NetworkMgrMacos(); 26 | 27 | protected: 28 | int setLocalhostDNS(); 29 | int unsetLocalhostDNS(); 30 | int getStateDNS(bool reportNoChange); 31 | int testQuery(); 32 | std::vector getNetworks(); 33 | 34 | private slots: 35 | void on_setLocalhost_finished(int exitCode, QProcess::ExitStatus); 36 | void on_unsetLocalhost_finished(int exitCode, QProcess::ExitStatus); 37 | void on_getNetworkState_finished(int exitCode, QProcess::ExitStatus exitStatus); 38 | void on_testQuery_finished(int exitCode, QProcess::ExitStatus exitStatus); 39 | void on_getNetworkState_readyReadStdout(); 40 | 41 | private: 42 | RunHelperTaskMacos *m_setLocalhost; 43 | RunHelperTaskMacos *m_unsetLocalhost; 44 | RunHelperTaskMacos *m_getNetworkState; 45 | RunHelperTaskMacos *m_getActiveNetworks; 46 | RunHelperTaskMacos *m_getSSID; 47 | RunTaskMacos *m_testQuery; 48 | QString m_getNetworkState_output; 49 | }; 50 | 51 | #endif // NETWORKMGRMACOS_H 52 | -------------------------------------------------------------------------------- /os/macos/runtask_macos.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "runtask_macos.h" 17 | 18 | 19 | RunTaskMacos::RunTaskMacos(const QString command, QObject *parent) : 20 | QProcess(parent), 21 | m_command(command) 22 | { 23 | setProgram(m_command); 24 | } 25 | 26 | RunTaskMacos::~RunTaskMacos() 27 | { 28 | if (state() == Running) { 29 | terminate(); 30 | waitForFinished(); 31 | } 32 | } 33 | 34 | void RunTaskMacos::start() 35 | { 36 | QProcess::start(m_command, ReadWrite); 37 | } 38 | 39 | //static const char STUBBY_UI_HELPER[] = "/usr/local/sbin/stubby-ui-helper"; 40 | 41 | // TODO: MUST BE UPDATED ON INSTALL 42 | static const char STUBBY_UI_HELPER[] = "/Applications/StubbyManager.app/Contents/MacOS/stubby-ui-helper"; 43 | 44 | 45 | const char *RunHelperTaskMacos::RIGHT_DAEMON_RUN = "net.getdnsapi.stubby.daemon.run"; 46 | const char *RunHelperTaskMacos::RIGHT_DNS_LOCAL = "net.getdnsapi.stubby.dns.local"; 47 | 48 | RunHelperTaskMacos::RunHelperTaskMacos(const QString command, QString need_right, const QString config, QObject *parent, MainWindow *mainwindow) : 49 | QProcess(parent), 50 | m_command(command), 51 | m_need_right(need_right), 52 | m_config(config), 53 | m_mainwindow(mainwindow) 54 | { 55 | setProgram(STUBBY_UI_HELPER); 56 | 57 | OSStatus oss = AuthorizationCreate(NULL, NULL, 0, &m_auth_ref); 58 | assert(oss == errAuthorizationSuccess); 59 | //qDebug() << __FILE__ << ":" << __FUNCTION__ << "Auth create " << (oss == errAuthorizationSuccess); 60 | 61 | // Ensure rights have been created. 62 | oss = AuthorizationRightGet(RIGHT_DAEMON_RUN, NULL); 63 | assert(oss == errAuthorizationSuccess); 64 | //qDebug() << __FILE__ << ":" << __FUNCTION__ << "Auth daemon " << (oss == errAuthorizationSuccess); 65 | oss = AuthorizationRightGet(RIGHT_DNS_LOCAL, NULL); 66 | assert(oss == errAuthorizationSuccess); 67 | //qDebug() << __FILE__ << ":" << __FUNCTION__ << "Auth dns " << (oss == errAuthorizationSuccess); 68 | } 69 | 70 | RunHelperTaskMacos::~RunHelperTaskMacos() 71 | { 72 | AuthorizationFree(m_auth_ref, kAuthorizationFlagDefaults); 73 | 74 | //qDebug() << __FILE__ << ":" << __FUNCTION__; 75 | if (state() == Running) { 76 | terminate(); 77 | waitForFinished(); 78 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "waited for finish"; 79 | } 80 | } 81 | 82 | int RunHelperTaskMacos::execute() 83 | { 84 | QString cmd = makeCommandLine(); 85 | if (cmd.isNull()) { 86 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "auth failed"; 87 | return 1; 88 | } 89 | else { 90 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "executing " << cmd; 91 | int result = QProcess::execute(cmd); 92 | qInfo("Result of cmd execution is %d", result); 93 | if (result == -2) 94 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "Command could not be executed, process not found (-2)" << cmd; 95 | if (result == -1) 96 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "Command returned -1 " << cmd; 97 | return result; 98 | } 99 | } 100 | 101 | void RunHelperTaskMacos::start() 102 | { 103 | QString cmd = makeCommandLine(); 104 | if (cmd.isNull()) 105 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "auth failed"; 106 | else { 107 | qDebug() << __FILE__ << ":" << __FUNCTION__ << "starting " << cmd; 108 | QProcess::start(cmd, ReadWrite); 109 | } 110 | } 111 | 112 | QString RunHelperTaskMacos::makeCommandLine() 113 | { 114 | QString cmd(STUBBY_UI_HELPER); 115 | 116 | if ( !m_need_right.isEmpty() ) { 117 | AuthorizationItem right_detail[] = { 118 | { NULL, 0, NULL, 0 }, 119 | }; 120 | AuthorizationRights the_right = { 1, &right_detail[0] }; 121 | OSStatus oss; 122 | QByteArray needed_right = m_need_right.toUtf8(); 123 | right_detail[0].name = needed_right.constData(); 124 | 125 | oss = AuthorizationCopyRights( 126 | m_auth_ref, 127 | &the_right, 128 | kAuthorizationEmptyEnvironment, 129 | kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize, 130 | NULL); 131 | if (oss != errAuthorizationSuccess) 132 | return NULL; 133 | 134 | QString ext_auth = makeExternalAuth(); 135 | if (ext_auth.isEmpty()) 136 | return NULL; 137 | 138 | cmd += " -auth "; 139 | cmd += ext_auth; 140 | } 141 | 142 | if ( !m_config.isEmpty() ) { 143 | cmd += " -config "; 144 | cmd += m_config; 145 | } 146 | 147 | cmd += " " + m_command; 148 | return cmd; 149 | } 150 | 151 | QString RunHelperTaskMacos::makeExternalAuth() 152 | { 153 | QString res; 154 | AuthorizationExternalForm auth_ext_form; 155 | 156 | OSStatus oss = AuthorizationMakeExternalForm(m_auth_ref, &auth_ext_form); 157 | if ( oss == errAuthorizationSuccess) 158 | for (size_t i = 0; i < kAuthorizationExternalFormLength; ++i) { 159 | // Turn into a printable string of hex digits. 160 | char b = auth_ext_form.bytes[i]; 161 | char c; 162 | 163 | c = (b >> 4) & 0xf; 164 | res.append(c >= 10 ? 'a' + c - 10 : '0' + c); 165 | c = b & 0xf; 166 | res.append(c >= 10 ? 'a' + c - 10 : '0' + c); 167 | } 168 | return res; 169 | } 170 | -------------------------------------------------------------------------------- /os/macos/runtask_macos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef RUNTASK_MACOS_H 10 | #define RUNTASK_MACOS_H 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | class MainWindow; 18 | 19 | 20 | class RunTaskMacos : public QProcess 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | RunTaskMacos(const QString command, QObject *parent = 0); 26 | virtual ~RunTaskMacos(); 27 | void start(); 28 | 29 | private: 30 | QString m_command; 31 | }; 32 | 33 | class RunHelperTaskMacos : public QProcess 34 | { 35 | Q_OBJECT 36 | 37 | public: 38 | RunHelperTaskMacos(const QString command, QString need_right = QString(), const QString config = QString(), QObject *parent = 0, MainWindow *mainwindow = 0); 39 | virtual ~RunHelperTaskMacos(); 40 | int execute(); 41 | void start(); 42 | 43 | static const char *RIGHT_DAEMON_RUN; 44 | static const char *RIGHT_DNS_LOCAL; 45 | 46 | private: 47 | QString makeCommandLine(); 48 | QString makeExternalAuth(); 49 | 50 | QString m_command; 51 | QString m_need_right; 52 | QString m_config; 53 | MainWindow *m_mainwindow; 54 | AuthorizationRef m_auth_ref; 55 | }; 56 | 57 | #endif // RUNTASK_MACOS_H 58 | -------------------------------------------------------------------------------- /os/macos/servicemanager_macos.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "mainwindow.h" 13 | #include "servicemanager_macos.h" 14 | 15 | 16 | ServiceMgrMacos::ServiceMgrMacos(MainWindow *parent) : 17 | ServiceMgr(parent), 18 | m_getStateofService(0), 19 | m_startService(0), 20 | m_stopService(0), 21 | m_getStateofService_output("") 22 | 23 | { 24 | qInfo("Creating Macos service mgr"); 25 | 26 | m_getStateofService = new RunHelperTaskMacos("list", QString(), QString(), this, parent); 27 | connect(m_getStateofService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_getStateofService_finished(int, QProcess::ExitStatus))); 28 | connect(m_getStateofService, SIGNAL(readyReadStandardOutput()), this, SLOT(on_getStateofService_readyReadStdout())); 29 | 30 | m_startService = new RunHelperTaskMacos("start", RunHelperTaskMacos::RIGHT_DAEMON_RUN, QString(), this, parent); 31 | m_stopService = new RunHelperTaskMacos("stop", RunHelperTaskMacos::RIGHT_DAEMON_RUN, QString(), this, parent); 32 | } 33 | 34 | ServiceMgrMacos::~ServiceMgrMacos() 35 | { 36 | } 37 | 38 | int ServiceMgrMacos::getStateofService() { 39 | qInfo("gettting macos state"); 40 | m_getStateofService_output = ""; 41 | m_getStateofService->start(); 42 | return 0; 43 | } 44 | 45 | int ServiceMgrMacos::startService(QString configfile, int loglevel) 46 | { 47 | connect(m_startService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_startService_finished(int, QProcess::ExitStatus))); 48 | m_startService->start(); 49 | return 0; 50 | } 51 | 52 | int ServiceMgrMacos::stopService() 53 | { 54 | connect(m_stopService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_stopService_finished(int, QProcess::ExitStatus))); 55 | m_stopService->start(); 56 | return 0; 57 | } 58 | 59 | int ServiceMgrMacos::restartService() 60 | { 61 | connect(m_stopService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_restartServiceStopper_finished(int, QProcess::ExitStatus))); 62 | m_stopService->start(); 63 | return 0; 64 | } 65 | 66 | /* private slots to handle QProcess signals */ 67 | 68 | void ServiceMgrMacos::on_getStateofService_finished(int, QProcess::ExitStatus exitStatus) 69 | { 70 | if (exitStatus == QProcess::NormalExit) { 71 | /* search for "PID" = integer in the text */ 72 | QRegularExpression pidRegEx("\"PID\" = \\d+;"); 73 | QRegularExpressionMatch match; 74 | qInfo("%s", m_getStateofService_output.toLatin1().data()); 75 | match = pidRegEx.match(m_getStateofService_output); 76 | if (match.hasMatch()) { 77 | m_serviceState = Running; 78 | m_mainwindow->statusMsg("Status: Stubby service running."); 79 | emit serviceStateChanged(m_serviceState); 80 | } else { 81 | m_serviceState = Stopped; 82 | m_mainwindow->statusMsg("Status: Stubby service stopped."); 83 | emit serviceStateChanged(m_serviceState); 84 | } 85 | } else { 86 | qInfo("Checker process failed"); 87 | m_serviceState = Unknown; 88 | m_mainwindow->statusMsg("Status: Problem with Stubby service - state unknown."); 89 | emit serviceStateChanged(m_serviceState); 90 | } 91 | } 92 | 93 | void ServiceMgrMacos::on_getStateofService_readyReadStdout() 94 | { 95 | m_getStateofService_output = m_getStateofService_output + QString::fromLatin1(m_getStateofService->readAllStandardOutput().data()); 96 | } 97 | 98 | void ServiceMgrMacos::on_startService_finished(int exitCode, QProcess::ExitStatus exitStatus) 99 | { 100 | qDebug("Exit status %d, launchstl exit code %d", exitStatus, exitCode); 101 | disconnect(m_startService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_startService_finished(int, QProcess::ExitStatus))); 102 | getState(); 103 | } 104 | 105 | void ServiceMgrMacos::on_restartServiceStarter_finished(int exitCode, QProcess::ExitStatus exitStatus) 106 | { 107 | qDebug("Exit status %d, launchstl exit code %d", exitStatus, exitCode); 108 | disconnect(m_startService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_restartServiceStarter_finished(int, QProcess::ExitStatus))); 109 | getState(); 110 | } 111 | 112 | void ServiceMgrMacos::on_stopService_finished(int exitCode, QProcess::ExitStatus exitStatus) 113 | { 114 | qDebug("Exit status %d, launchstl exit code %d", exitStatus, exitCode); 115 | disconnect(m_stopService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_stopService_finished(int, QProcess::ExitStatus))); 116 | getState(); 117 | } 118 | 119 | void ServiceMgrMacos::on_restartServiceStopper_finished(int exitCode, QProcess::ExitStatus exitStatus) 120 | { 121 | qDebug("Exit status %d, launchstl exit code %d", exitStatus, exitCode); 122 | disconnect(m_stopService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_restartServiceStopper_finished(int, QProcess::ExitStatus))); 123 | connect(m_startService, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(on_restartServiceStarter_finished(int, QProcess::ExitStatus))); 124 | m_startService->start(); 125 | } 126 | 127 | ServiceMgr *ServiceMgr::factory(MainWindow *parent) 128 | { 129 | return new ServiceMgrMacos(parent); 130 | } 131 | -------------------------------------------------------------------------------- /os/macos/servicemanager_macos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef SERVICEMGRMACOS_H 10 | #define SERVICEMGRMACOS_H 11 | 12 | #include 13 | 14 | #include "servicemanager.h" 15 | #include "os/macos/runtask_macos.h" 16 | 17 | class MainWindow; 18 | 19 | 20 | class ServiceMgrMacos : public ServiceMgr 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | ServiceMgrMacos(MainWindow *parent); 26 | virtual ~ServiceMgrMacos(); 27 | 28 | private slots: 29 | void on_getStateofService_finished(int, QProcess::ExitStatus); 30 | void on_getStateofService_readyReadStdout(); 31 | void on_startService_finished(int, QProcess::ExitStatus); 32 | void on_stopService_finished(int, QProcess::ExitStatus); 33 | void on_restartServiceStarter_finished(int exitCode, QProcess::ExitStatus exitStatus); 34 | void on_restartServiceStopper_finished(int exitCode, QProcess::ExitStatus exitStatus); 35 | 36 | private: 37 | RunHelperTaskMacos *m_getStateofService; 38 | RunHelperTaskMacos *m_startService; 39 | RunHelperTaskMacos *m_stopService; 40 | QString m_getStateofService_output; 41 | 42 | 43 | private: 44 | int getStateofService(); 45 | int startService(QString configfile = "", int loglevel = 6); 46 | int stopService(); 47 | int restartService(); 48 | }; 49 | 50 | #endif // SERVICEMGRMACOS_H 51 | -------------------------------------------------------------------------------- /os/windows/StubbyManager.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/os/windows/StubbyManager.xml -------------------------------------------------------------------------------- /os/windows/StubbySetDns.ps1: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Sinodun Internet Technologies Ltd. 2 | # 3 | # This Source Code Form is subject to the terms of the Mozilla Public 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this 5 | # file, you can obtain one at https://mozilla.org/MPL/2.0/. 6 | 7 | 8 | Param([Switch] $Loopback = $false) 9 | 10 | $ErrorActionPreference = "Stop" 11 | 12 | Try { 13 | Get-NetAdapter -Physical | ForEach-Object { 14 | $ifname = $_.Name 15 | If ($Loopback) { 16 | set-dnsclientserveraddress $ifname -ServerAddresses ("127.0.0.1","0::1") 17 | } Else { 18 | set-dnsclientserveraddress $ifname -ResetServerAddresses 19 | } 20 | } 21 | } 22 | Catch { 23 | } 24 | 25 | exit $LASTEXITCODE 26 | -------------------------------------------------------------------------------- /os/windows/configmanager_windows.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "configmanager_windows.h" 24 | #include "exceptions_windows.h" 25 | #include "mainwindow.h" 26 | 27 | ConfigMgrWindows::ConfigMgrWindows(MainWindow *parent) 28 | : ConfigMgr(parent) 29 | { 30 | } 31 | 32 | ConfigMgrWindows::~ConfigMgrWindows() 33 | { 34 | } 35 | 36 | static std::string GetKnownFolder(REFKNOWNFOLDERID rfid, const std::string& appdir) 37 | { 38 | PWSTR path; 39 | HRESULT hr = SHGetKnownFolderPath(rfid, KF_FLAG_CREATE, NULL, &path); 40 | 41 | if ( SUCCEEDED(hr) ) 42 | { 43 | QString qstr = QString::fromWCharArray(path); 44 | CoTaskMemFree(path); 45 | 46 | // Both below need app dir appended. 47 | QDir dir(QDir::cleanPath(qstr)); 48 | return dir.filePath(QString::fromStdString(appdir)).toStdString(); 49 | } 50 | return "C:\\Program Data\\Stubby"; 51 | //throw windows_system_error("Can't find known folder"); 52 | } 53 | 54 | std::string ConfigMgrWindows::appDataDir() 55 | { 56 | return GetKnownFolder(FOLDERID_ProgramData, APPDIRNAME); 57 | } 58 | 59 | std::string ConfigMgrWindows::appDir() 60 | { 61 | return QCoreApplication::applicationDirPath().toStdString(); 62 | } 63 | 64 | ConfigMgr *ConfigMgr::factory(MainWindow *parent) 65 | { 66 | return new ConfigMgrWindows(parent); 67 | } 68 | -------------------------------------------------------------------------------- /os/windows/configmanager_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef CONFIGMGRWINDOWS_H 10 | #define CONFIGMGRWINDOWS_H 11 | 12 | #include 13 | 14 | #include "configmanager.h" 15 | 16 | class ConfigMgrWindows : public ConfigMgr 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | ConfigMgrWindows(MainWindow *parent); 22 | virtual ~ConfigMgrWindows(); 23 | 24 | protected: 25 | virtual std::string appDataDir(); 26 | virtual std::string appDir(); 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /os/windows/exceptions_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | /* ; -*-C++-*- */ 10 | #ifndef EXCEPTIONS_WINDOWS_H 11 | #define EXCEPTIONS_WINDOWS_H 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | class windows_system_error : public std::system_error 19 | { 20 | public: 21 | windows_system_error(DWORD err, const std::string& what) 22 | : std::system_error(err, std::system_category(), what) 23 | { 24 | } 25 | 26 | windows_system_error(DWORD err, const char* what) 27 | : std::system_error(err, std::system_category(), what) 28 | { 29 | } 30 | 31 | windows_system_error(const std::string& what) 32 | : windows_system_error(GetLastError(), what) 33 | { 34 | } 35 | 36 | windows_system_error(const char* what) 37 | : windows_system_error(GetLastError(), what) 38 | { 39 | } 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /os/windows/logmanager_windows.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "logmanager_windows.h" 14 | #include "mainwindow.h" 15 | 16 | const char SVCNAME[] = "Stubby"; 17 | 18 | static void winerr(const char* operation, DWORD err) 19 | { 20 | char msg[512]; 21 | 22 | if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 23 | NULL, 24 | err, 25 | 0, 26 | msg, 27 | sizeof(msg), 28 | NULL) == 0 ) 29 | qCritical("Error: %s: errno=%d\n", operation, err); 30 | else 31 | qCritical("Error: %s: %s\n", operation, msg); 32 | } 33 | 34 | static void winlasterr(const char* operation) 35 | { 36 | winerr(operation, GetLastError()); 37 | } 38 | 39 | LogMgrWindows::LogMgrWindows(MainWindow *parent) : 40 | QObject(parent), 41 | m_mainWindow(parent), 42 | m_log(NULL), 43 | m_eventResources(NULL), 44 | m_logTimer(NULL) 45 | { 46 | 47 | m_log = OpenEventLog(NULL, SVCNAME); 48 | if ( !m_log ) 49 | winlasterr("Open event log"); 50 | 51 | char subkey[128]; 52 | char fname[MAX_PATH]; 53 | LSTATUS status; 54 | DWORD datasize; 55 | 56 | snprintf(subkey, sizeof(subkey), 57 | "SYSTEM\\CurrentControlSet\\Services" 58 | "\\EventLog\\Application\\%s", SVCNAME); 59 | status = RegGetValue(HKEY_LOCAL_MACHINE, subkey, "EventMessageFile", 60 | RRF_RT_REG_SZ, NULL, fname, &datasize); 61 | if ( status == ERROR_SUCCESS ) 62 | m_eventResources = LoadLibraryEx(fname, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE); 63 | if ( m_eventResources == NULL ) 64 | winlasterr("Load resources module"); 65 | // Read and throw away previous log entries. 66 | readServiceLog(); 67 | 68 | m_logTimer = new QTimer(this); 69 | connect(m_logTimer, &QTimer::timeout, this, QOverload<>::of(&LogMgrWindows::logTimerExpired)); 70 | } 71 | 72 | LogMgrWindows::~LogMgrWindows() 73 | { 74 | if ( m_eventResources ) 75 | FreeLibrary(m_eventResources); 76 | if ( m_log ) 77 | CloseEventLog(m_log); 78 | if (m_logTimer) { 79 | m_logTimer->stop(); 80 | delete m_logTimer; 81 | } 82 | } 83 | 84 | void LogMgrWindows::logTimerExpired() { 85 | QString log = (readServiceLog()); 86 | if (!log.isEmpty()) 87 | m_mainWindow->logMsg(log); 88 | } 89 | 90 | QString LogMgrWindows::readServiceLog() 91 | { 92 | QString res; 93 | 94 | if ( !m_log ) 95 | return res; 96 | 97 | std::vector evtBuf(sizeof(EVENTLOGRECORD) * 10); 98 | 99 | for(;;) 100 | { 101 | DWORD bytesRead; 102 | DWORD minBytesNeeded; 103 | 104 | if ( ReadEventLog(m_log, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, 105 | evtBuf.data(), static_cast(evtBuf.capacity()), 106 | &bytesRead, &minBytesNeeded) == 0 ) 107 | { 108 | DWORD err = GetLastError(); 109 | if ( err == ERROR_HANDLE_EOF ) 110 | break; 111 | if ( err != ERROR_INSUFFICIENT_BUFFER ) 112 | { 113 | winerr("Read event log", err); 114 | break; 115 | } 116 | evtBuf.resize(minBytesNeeded); 117 | if ( ReadEventLog(m_log, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, 118 | evtBuf.data(), static_cast(evtBuf.capacity()), 119 | &bytesRead, &minBytesNeeded) == 0 ) 120 | { 121 | winerr("Read event log", err); 122 | break; 123 | } 124 | } 125 | 126 | char* pStart = evtBuf.data(); 127 | char* pEnd = pStart + bytesRead; 128 | 129 | while ( pStart < pEnd ) 130 | { 131 | EVENTLOGRECORD* evt = reinterpret_cast(pStart); 132 | pStart += evt->Length; 133 | 134 | if ( logMessageSource(evt) == SVCNAME ) { 135 | res.append(formatLogMessage(evt)); 136 | } 137 | } 138 | } 139 | return res; 140 | } 141 | 142 | QString LogMgrWindows::logMessageSource(PEVENTLOGRECORD pevt) 143 | { 144 | // The source name follows the EVENTLOGRECORD structure in memory. 145 | const char* p = reinterpret_cast(pevt) + sizeof(EVENTLOGRECORD); 146 | return QString::fromUtf8(p); 147 | } 148 | 149 | QString LogMgrWindows::formatLogMessage(PEVENTLOGRECORD pevt) 150 | { 151 | std::time_t t = static_cast(pevt->TimeGenerated); 152 | std::tm tm; 153 | char msg[512]; 154 | const char* etype; 155 | std::ostringstream out; 156 | 157 | switch (pevt->EventType) 158 | { 159 | case EVENTLOG_ERROR_TYPE: 160 | etype = "ERROR"; 161 | break; 162 | 163 | case EVENTLOG_WARNING_TYPE: 164 | etype = "WARN"; 165 | break; 166 | 167 | default: 168 | etype = "INFO"; 169 | break; 170 | } 171 | 172 | localtime_s(&tm, &t); 173 | std::strftime(msg, sizeof(msg), "%F %T %z", &tm); 174 | out << msg << ' ' << etype << ' '; 175 | 176 | std::vector args(pevt->NumStrings); 177 | char* p = reinterpret_cast(pevt) + pevt->StringOffset; 178 | for ( int i = 0; i < pevt->NumStrings; ++i ) 179 | { 180 | args[i] = p; 181 | p += strlen(p) + 1; 182 | } 183 | 184 | char** argv = args.data(); 185 | 186 | if ( m_eventResources && 187 | FormatMessage( 188 | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, 189 | m_eventResources, 190 | pevt->EventID, 191 | 0, 192 | msg, 193 | sizeof(msg), 194 | reinterpret_cast(argv)) ) 195 | { 196 | for ( char* endp = msg + strlen(msg) - 1; 197 | endp >= msg && (*endp == '\r' || *endp == '\n' || *endp == '.' ); 198 | --endp ) { 199 | *endp = '\0'; 200 | } 201 | out << " " << msg; 202 | } 203 | else 204 | { 205 | for (auto s : args) 206 | out << " " << s; 207 | } 208 | out << '\n'; 209 | 210 | return QString(out.str().c_str()); 211 | } 212 | 213 | 214 | void LogMgrWindows::start() 215 | { 216 | m_logTimer->start(500); 217 | } 218 | 219 | void LogMgrWindows::stop() 220 | { 221 | m_logTimer->stop(); 222 | } 223 | 224 | ILogMgr *ILogMgr::factory(MainWindow *parent) 225 | { 226 | return new LogMgrWindows(parent); 227 | } 228 | 229 | -------------------------------------------------------------------------------- /os/windows/logmanager_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef LOGMANAGERWINDOWS_H 10 | #define LOGMANAGERWINDOWS_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "logmanager.h" 19 | 20 | 21 | 22 | class LogMgrWindows : public QObject, public ILogMgr 23 | { 24 | Q_OBJECT 25 | 26 | Q_INTERFACES(ILogMgr) 27 | 28 | public: 29 | LogMgrWindows(MainWindow *parent = 0); 30 | ~LogMgrWindows(); 31 | 32 | void start(); 33 | void stop(); 34 | 35 | signals: 36 | void alert(bool on); 37 | 38 | protected: 39 | MainWindow *m_mainWindow; 40 | 41 | private: 42 | 43 | QString logMessageSource(PEVENTLOGRECORD pevt); 44 | QString formatLogMessage(PEVENTLOGRECORD pevt); 45 | QString readServiceLog(); 46 | HANDLE m_log; 47 | HMODULE m_eventResources; 48 | 49 | void logTimerExpired(); 50 | QTimer *m_logTimer; 51 | 52 | }; 53 | 54 | #endif // LOGMANAGERWINDOWS_H 55 | -------------------------------------------------------------------------------- /os/windows/networkinterface_windows.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | 12 | #include "networkinterface_windows.hpp" 13 | 14 | NetworkInterfaceWindows::NetworkInterfaceWindows( 15 | const std::string& name, 16 | const std::string& adapter_name, 17 | const std::string& description, 18 | const std::string& dns_suffix, 19 | const std::string& ssid, 20 | bool is_resolver_loopback, 21 | bool is_running, 22 | DWORD if_type, 23 | IF_OPER_STATUS oper_status) 24 | : name_(name), adapter_name_(adapter_name), 25 | description_(description), dns_suffix_(dns_suffix), ssid_(ssid), 26 | is_resolver_loopback_(is_resolver_loopback), 27 | is_running_(is_running), 28 | if_type_(if_type), 29 | oper_status_(oper_status) 30 | { 31 | } 32 | 33 | std::string NetworkInterfaceWindows::name() const 34 | { 35 | return name_; 36 | } 37 | 38 | bool NetworkInterfaceWindows::is_resolver_loopback() const 39 | { 40 | return is_resolver_loopback_; 41 | } 42 | 43 | bool NetworkInterfaceWindows::is_running() const 44 | { 45 | return is_running_; 46 | } 47 | 48 | bool NetworkInterfaceWindows::is_up() const 49 | { 50 | return oper_status_ & IfOperStatusUp; 51 | } 52 | 53 | bool NetworkInterfaceWindows::is_wireless() const 54 | { 55 | return if_type_ == IF_TYPE_IEEE80211; 56 | } 57 | 58 | bool NetworkInterfaceWindows::is_ethernet() const 59 | { 60 | return if_type_ == IF_TYPE_ETHERNET_CSMACD; 61 | } 62 | 63 | std::string NetworkInterfaceWindows::ssid() const 64 | { 65 | return ssid_; 66 | } 67 | -------------------------------------------------------------------------------- /os/windows/networkinterface_windows.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | 10 | #ifndef NETWORKINTERFACEWINDOWS_H 11 | #define NETWORKINTERFACEWINDOWS_H 12 | 13 | #include 14 | #include 15 | 16 | #include "networkinterface.hpp" 17 | 18 | class NetworkInterfaceWindows : public NetworkInterface 19 | { 20 | public: 21 | NetworkInterfaceWindows(const std::string& name, 22 | const std::string& adapter_name, 23 | const std::string& descripton, 24 | const std::string& dns_suffix, 25 | const std::string& ssid, 26 | bool is_resolver_loopback, 27 | bool is_running, 28 | DWORD if_type, 29 | IF_OPER_STATUS oper_status); 30 | ~NetworkInterfaceWindows() = default; 31 | 32 | std::string name() const override; 33 | 34 | bool is_resolver_loopback() const override; 35 | bool is_running() const override; 36 | bool is_up() const override; 37 | bool is_wireless() const override; 38 | bool is_ethernet() const override; 39 | 40 | virtual std::string ssid() const override; 41 | 42 | 43 | private: 44 | std::string name_; 45 | std::string adapter_name_; 46 | std::string description_; 47 | std::string dns_suffix_; 48 | std::string ssid_; 49 | bool is_resolver_loopback_; 50 | bool is_running_; 51 | DWORD if_type_; 52 | IF_OPER_STATUS oper_status_; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /os/windows/networkmanager_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef NETWORKMGRWINDOWS_H 10 | #define NETWORKMGRWINDOWS_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "networkinterface_windows.hpp" 18 | #include "networkmanager.h" 19 | 20 | 21 | class QueryTaskWindows : public QProcess 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | QueryTaskWindows(QObject *parent = 0); 27 | virtual ~QueryTaskWindows(); 28 | void start(); 29 | }; 30 | 31 | class NetworkMgrWindows : public NetworkMgr 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | NetworkMgrWindows(MainWindow *parent = 0); 37 | virtual ~NetworkMgrWindows(); 38 | 39 | protected: 40 | int setLocalhostDNS() override; 41 | int unsetLocalhostDNS() override; 42 | int getStateDNS(bool reportChange) override; 43 | int testQuery() override; 44 | std::map getNetworks() override; 45 | 46 | private slots: 47 | void on_testQuery_finished(int exitCode, QProcess::ExitStatus exitStatus); 48 | void on_networkInferfaces_changed(const QNetworkConfiguration& cfg); 49 | 50 | private: 51 | std::vector> getInterfaces(); 52 | std::vector interfaces; 53 | 54 | bool isRunning() const; 55 | bool isResolverLoopback() const; 56 | void reload(); 57 | 58 | QProcess *m_testQuery; 59 | QNetworkConfigurationManager m_networkConfig; 60 | }; 61 | 62 | #endif // NETWORKMGRWINDOWS_H 63 | -------------------------------------------------------------------------------- /os/windows/servicemanager_windows.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "mainwindow.h" 21 | #include "servicemanager_windows.h" 22 | 23 | const char SVCNAME[] = "Stubby"; 24 | 25 | static void CALLBACK notify_callback_trampoline(void* param) 26 | { 27 | SERVICE_NOTIFY* sn = static_cast(param); 28 | ServiceMgrWindows* smw = static_cast(sn->pContext); 29 | smw->notifyCallback(); 30 | } 31 | 32 | static void winerr(const char* operation, DWORD err) 33 | { 34 | char msg[512]; 35 | 36 | if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 37 | NULL, 38 | err, 39 | 0, 40 | msg, 41 | sizeof(msg), 42 | NULL) == 0 ) 43 | qCritical("Error: %s: errno=%d\n", operation, err); 44 | else 45 | qCritical("Error: %s: %s\n", operation, msg); 46 | } 47 | 48 | static void winlasterr(const char* operation) 49 | { 50 | winerr(operation, GetLastError()); 51 | } 52 | 53 | ServiceMgrWindows::ServiceMgrWindows(MainWindow *parent) : 54 | ServiceMgr(parent), m_schSCManager(NULL), m_schService(NULL), 55 | m_ConfigFile(QDir(QCoreApplication::applicationDirPath()), "stubbyservice.yml") 56 | { 57 | qInfo("Creating Windows service mgr"); 58 | m_schSCManager = OpenSCManager( 59 | NULL, // local computer 60 | NULL, // ServicesActive database 61 | STANDARD_RIGHTS_WRITE); // need to change state 62 | if ( !m_schSCManager ) 63 | winlasterr("Open service manager"); 64 | else 65 | { 66 | m_schService = OpenService( 67 | m_schSCManager, // SCM database 68 | SVCNAME, // name of service 69 | SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS); // intention 70 | if ( m_schService ) 71 | { 72 | DWORD err; 73 | 74 | m_serviceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; 75 | m_serviceNotify.pfnNotifyCallback = reinterpret_cast(notify_callback_trampoline); 76 | m_serviceNotify.pContext = this; 77 | 78 | err = NotifyServiceStatusChange( 79 | m_schService, 80 | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING | 81 | SERVICE_NOTIFY_STOP_PENDING | SERVICE_NOTIFY_STOPPED, 82 | &m_serviceNotify); 83 | if ( err != ERROR_SUCCESS ) 84 | winerr("Notify status change", err); 85 | } 86 | else 87 | winlasterr("Open service"); 88 | } 89 | } 90 | 91 | ServiceMgrWindows::~ServiceMgrWindows() 92 | { 93 | if ( m_schService ) 94 | CloseServiceHandle(m_schService); 95 | if ( m_schSCManager ) 96 | CloseServiceHandle(m_schSCManager); 97 | } 98 | 99 | void ServiceMgrWindows::notifyCallback() 100 | { 101 | //qDebug("Notify callback status %d", m_serviceNotify.dwNotificationStatus); 102 | if ( m_serviceNotify.dwNotificationStatus == ERROR_SUCCESS ) 103 | updateState(m_serviceNotify.ServiceStatus.dwCurrentState); 104 | 105 | DWORD err = NotifyServiceStatusChange( 106 | m_schService, 107 | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING | 108 | SERVICE_NOTIFY_STOP_PENDING | SERVICE_NOTIFY_STOPPED, 109 | &m_serviceNotify); 110 | if ( err != ERROR_SUCCESS ) 111 | winerr("Notify status change", err); 112 | } 113 | 114 | void ServiceMgrWindows::updateState(DWORD state) 115 | { 116 | const char* state_msg; 117 | ServiceMgr::ServiceState oldState = m_serviceState; 118 | 119 | switch(state) 120 | { 121 | case SERVICE_RUNNING: 122 | m_serviceState = Running; 123 | state_msg = "running"; 124 | break; 125 | 126 | case SERVICE_START_PENDING: 127 | m_serviceState = Starting; 128 | state_msg = "starting"; 129 | break; 130 | 131 | case SERVICE_STOP_PENDING: 132 | m_serviceState = Stopping; 133 | state_msg = "stopping"; 134 | break; 135 | 136 | case SERVICE_STOPPED: 137 | m_serviceState = Stopped; 138 | state_msg = "stopped"; 139 | break; 140 | 141 | default: 142 | m_serviceState = Unknown; 143 | state_msg = "unknown"; 144 | qWarning("Unexpected status: %d", state); 145 | break; 146 | } 147 | 148 | if (oldState != m_serviceState 149 | // || (m_mainwindow->getUpdateState() == MainWindow::UpdateState::Init 150 | || m_mainwindow->getUpdateState() == MainWindow::UpdateState::Probe) { 151 | m_mainwindow->statusMsg(QString("Status: Stubby service state is %1").arg(state_msg)); 152 | emit serviceStateChanged(m_serviceState); 153 | } 154 | } 155 | 156 | int ServiceMgrWindows::getStateofService() 157 | { 158 | //qInfo("getting service state"); 159 | 160 | if ( m_schService ) { 161 | SERVICE_STATUS st; 162 | 163 | if ( QueryServiceStatus( 164 | m_schService, // service 165 | &st // result 166 | ) != 0 ) { 167 | updateState(st.dwCurrentState); 168 | return 0; 169 | } 170 | } 171 | 172 | winlasterr("Query service failed"); 173 | return 1; 174 | } 175 | 176 | int ServiceMgrWindows::startService(QString configfile, int loglevel) 177 | { 178 | qInfo("start service"); 179 | 180 | TCHAR loglevelstr[2]; 181 | loglevelstr[0] = '0' + loglevel; 182 | loglevelstr[1] = '\0'; 183 | 184 | // QString to const char * must be done in two steps or else QByteArray is 185 | // destoyed before const data accessed. 186 | QByteArray conf_ba = configfile.toUtf8(); 187 | QByteArray def_conf_ba = m_ConfigFile.filePath().toUtf8(); 188 | LPCTSTR args[2] = { 189 | loglevelstr, 190 | configfile.isEmpty() ? def_conf_ba.constData() : conf_ba.constData() 191 | }; 192 | int nargs = 2; 193 | 194 | if ( m_schService && StartService(m_schService, nargs, args) ) 195 | return 0; 196 | 197 | winlasterr("Start service failed"); 198 | return 1; 199 | } 200 | 201 | int ServiceMgrWindows::stopService() 202 | { 203 | qInfo("stop service"); 204 | 205 | SERVICE_STATUS st; 206 | 207 | if ( m_schService && ControlService(m_schService, SERVICE_CONTROL_STOP, &st) ) 208 | return 0; 209 | 210 | winlasterr("Stop service failed"); 211 | return 1; 212 | } 213 | 214 | int ServiceMgrWindows::restartService() 215 | { 216 | // Service start is triggered later from main windown 217 | qInfo("restart service"); 218 | return stopService(); 219 | } 220 | 221 | ServiceMgr *ServiceMgr::factory(MainWindow *parent) 222 | { 223 | return new ServiceMgrWindows(parent); 224 | } 225 | -------------------------------------------------------------------------------- /os/windows/servicemanager_windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef SERVICEMGRWINDOWS_H 10 | #define SERVICEMGRWINDOWS_H 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "servicemanager.h" 18 | 19 | class MainWindow; 20 | 21 | 22 | class ServiceMgrWindows : public ServiceMgr 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | ServiceMgrWindows(MainWindow *parent); 28 | virtual ~ServiceMgrWindows(); 29 | 30 | void notifyCallback(); 31 | 32 | private: 33 | int getStateofService(); 34 | int startService(QString configfile = "", int loglevel = 6); 35 | int stopService(); 36 | int restartService(); 37 | 38 | QString logMessageSource(PEVENTLOGRECORD pevt); 39 | QString formatLogMessage(PEVENTLOGRECORD pevt); 40 | void updateState(DWORD state); 41 | 42 | SC_HANDLE m_schSCManager; 43 | SC_HANDLE m_schService; 44 | SERVICE_NOTIFY m_serviceNotify; 45 | QFileInfo m_ConfigFile; 46 | }; 47 | 48 | #endif // SERVICEMGRWINDOWS_H 49 | -------------------------------------------------------------------------------- /os/windows/stubbygui.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinodun/Stubby_Manager/655523464ca44988a7d80f965fc2a2edf4275541/os/windows/stubbygui.ico -------------------------------------------------------------------------------- /os/windows/stubbygui.rc.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #if _DEBUG 12 | #define VER_DBG VS_FF_DEBUG 13 | #else 14 | #define VER_DBG 0 15 | #endif 16 | 17 | 18 | 1 ICON "stubbygui.ico" 19 | 20 | 1 VERSIONINFO 21 | FILEVERSION @VER_PRODUCTVERSION@ 22 | PRODUCTVERSION @VER_PRODUCTVERSION@ 23 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 24 | FILEFLAGS VER_DBG 25 | FILEOS VOS__WINDOWS32 26 | FILETYPE VFT_APP 27 | FILESUBTYPE VFT2_UNKNOWN 28 | BEGIN 29 | BLOCK "StringFileInfo" 30 | BEGIN 31 | BLOCK "040904E4" 32 | BEGIN 33 | VALUE "CompanyName", "Sinodun" 34 | VALUE "FileDescription", "Stubby Manager GUI" 35 | VALUE "FileVersion", "@VER_PRODUCTVERSION_STR@" 36 | VALUE "OriginalFilename", "stubby_gui.exe" 37 | VALUE "InternalName", "stubby_gui" 38 | VALUE "LegalCopyright", "(C) 2020 Sinodun." 39 | VALUE "ProductName", "Stubby Manager GUI" 40 | VALUE "ProductVersion", "@VER_PRODUCTVERSION_STR@" 41 | END 42 | END 43 | 44 | BLOCK "VarFileInfo" 45 | BEGIN 46 | /* US English (0x409), Windows ANSI codepage (1252). */ 47 | VALUE "Translation", 0x409, 1252 48 | END 49 | END 50 | -------------------------------------------------------------------------------- /os/windows/stubbygui.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 111 | 112 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /os/windows/windows_package_version.in: -------------------------------------------------------------------------------- 1 | @WINDOWS_PACKAGE_VERSION@ 2 | -------------------------------------------------------------------------------- /serverdatadialog.cpp: -------------------------------------------------------------------------------- 1 | #include "serverdatadialog.h" 2 | #include "ui_serverdatadialog.h" 3 | 4 | #include 5 | 6 | 7 | ServerDataDialog::ServerDataDialog(Config::Server& server, QWidget *parent) : 8 | QDialog(parent), 9 | ui(new Ui::serverdatadialog), 10 | m_server(server) 11 | { 12 | ui->setupUi(this); 13 | ui->serverNameData->setText(server.name.c_str()); 14 | ui->serverWebsiteData->setText(server.link.c_str()); 15 | ui->serverAddressData->setText(server.addresses[0].c_str()); 16 | //ui->serverAddressData->setInputMask("000.000.000.000;"); 17 | ui->serverAuthName->setText(server.tlsAuthName.c_str()); 18 | ui->serverPinData->setText(server.pubKeyDigestValue.c_str()); 19 | ui->v6AddressLabel->setVisible(false); 20 | ui->v6AddressEdit->setVisible(false); 21 | // remove question mark from the title bar 22 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 23 | 24 | ui->serverNameData->setToolTip("(Required) Set a user friendly name for this server"); 25 | ui->serverWebsiteData->setToolTip("Set a link to a website with information about this server/service"); 26 | ui->serverAddressData->setToolTip("(Required) The IPv4 Address for the server (IPv6 support coming soon)"); 27 | ui->serverAuthName->setToolTip("Specify the TLS authentication name to use when authenticating this server"); 28 | ui->serverPinData->setToolTip("Specify the pin (SPKI Digest Value to use when authenticating this server"); 29 | } 30 | 31 | ServerDataDialog::~ServerDataDialog() 32 | { 33 | delete ui; 34 | } 35 | 36 | void ServerDataDialog::on_applyButton_clicked() { 37 | qInfo("Validating server"); 38 | bool result = true; 39 | QString message; 40 | 41 | // server MUST have a name 42 | if (ui->serverNameData->text().isEmpty()) { 43 | message.append("ERRROR: Server must have a name\n"); 44 | result = false; 45 | } 46 | 47 | // server MUST have valid IP v4 address for now 48 | int pos; 49 | QString addr = ui->serverAddressData->text(); 50 | QRegExp rx("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); 51 | validator = new QRegExpValidator(rx, this); 52 | if (validator->validate(addr, pos) != QValidator::Acceptable) { 53 | message.append("ERRROR: The Main IPv4 address is not a valid format"); 54 | result = false; 55 | } 56 | //TODO: Add warning if no auth info 57 | 58 | if (result) { 59 | m_server.name = ui->serverNameData->text().toUtf8().constData(); 60 | m_server.link = ui->serverWebsiteData->text().toUtf8().constData();; 61 | m_server.addresses[0] = ui->serverAddressData->text().toUtf8().constData();; 62 | m_server.tlsAuthName = ui->serverAuthName->text().toUtf8().constData();; 63 | m_server.pubKeyDigestValue = ui->serverPinData->text().toUtf8().constData();; 64 | accept(); 65 | } 66 | else { 67 | ui->validationMessage->setText(message); 68 | return; 69 | } 70 | } 71 | 72 | void ServerDataDialog::on_discardButton_clicked() { 73 | reject(); 74 | } 75 | -------------------------------------------------------------------------------- /serverdatadialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERDATADIALOG_H 2 | #define SERVERDATADIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace Ui { 10 | class serverdatadialog; 11 | } 12 | 13 | class ServerDataDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit ServerDataDialog(Config::Server& server, QWidget *parent = nullptr); 19 | ~ServerDataDialog(); 20 | 21 | public slots: 22 | void on_applyButton_clicked(); 23 | void on_discardButton_clicked(); 24 | 25 | private: 26 | Ui::serverdatadialog *ui; 27 | QValidator *validator; 28 | Config::Server& m_server; 29 | }; 30 | 31 | #endif // SERVERDATADIALOG_H 32 | -------------------------------------------------------------------------------- /serverdatadialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | serverdatadialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 524 10 | 302 11 | 12 | 13 | 14 | 15 | 10 16 | 17 | 18 | 19 | Edit server 20 | 21 | 22 | 23 | :/images/stubby.ico:/images/stubby.ico 24 | 25 | 26 | 27 | 28 | 29 | -7 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 30 38 | 20 39 | 461 40 | 164 41 | 42 | 43 | 44 | 45 | 46 | 47 | Name* 48 | 49 | 50 | 51 | 52 | 53 | 54 | Website 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | IP Address* 68 | 69 | 70 | 71 | 72 | 73 | 74 | TLS Auth Name 75 | 76 | 77 | 78 | 79 | 80 | 81 | Pin 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | false 104 | 105 | 106 | Main IPv6 Address 107 | 108 | 109 | 110 | 111 | 112 | 113 | false 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 40 123 | 190 124 | 321 125 | 51 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 210 136 | 260 137 | 91 138 | 23 139 | 140 | 141 | 142 | Discard Edits 143 | 144 | 145 | 146 | 147 | 148 | 310 149 | 260 150 | 75 151 | 23 152 | 153 | 154 | 155 | Apply 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /serverstablemodel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "serverstablemodel.h" 13 | 14 | ServersTableModel::ServersTableModel(Config& config, Config::NetworkProfile networkProfile, QObject* parent) 15 | : m_config(config), m_networkProfile(networkProfile), QAbstractTableModel(parent) 16 | { 17 | 18 | } 19 | 20 | ServersTableModel::~ServersTableModel() 21 | { 22 | } 23 | 24 | int ServersTableModel::columnCount(const QModelIndex& parent) const 25 | { 26 | Q_UNUSED(parent); 27 | return 5; 28 | } 29 | 30 | int ServersTableModel::rowCount(const QModelIndex& parent) const 31 | { 32 | Q_UNUSED(parent); 33 | 34 | std::size_t res = 0; 35 | 36 | for ( const auto& s : m_config.servers ) 37 | if ( s.hidden.find(m_networkProfile) == s.hidden.end() ) 38 | res += s.addresses.size(); 39 | 40 | return static_cast(res); 41 | } 42 | 43 | QVariant ServersTableModel::data(const QModelIndex& index, int role) const 44 | { 45 | if ( !index.isValid() ) 46 | return QVariant(); 47 | 48 | int serverIndex, addressIndex; 49 | serverFromRow(index.row(), serverIndex, addressIndex); 50 | 51 | if ( serverIndex < 0 ) 52 | return QVariant(); 53 | 54 | const Config::Server& server(m_config.servers[serverIndex]); 55 | const std::string& address(server.addresses[addressIndex]); 56 | 57 | if ( role == Qt::DisplayRole ) 58 | { 59 | switch (index.column()) 60 | { 61 | case 1: // Name 62 | return QString::fromStdString(server.name); 63 | 64 | case 2: // Link 65 | return QString::fromStdString(server.link); 66 | 67 | case 3: // Address 68 | return QString::fromStdString(address); 69 | 70 | case 4: // TLS auth name 71 | return QString::fromStdString(server.tlsAuthName); 72 | 73 | case 5: // Key digest value 74 | return QString::fromStdString(server.pubKeyDigestValue); 75 | } 76 | } else if ( role == Qt::CheckStateRole ) 77 | { 78 | if ( index.column() == 0 ) 79 | { 80 | if ( server.inactive.find(m_networkProfile) == server.inactive.end() ) 81 | return Qt::Checked; 82 | else 83 | return Qt::Unchecked; 84 | } 85 | } 86 | else if (role == Qt::FontRole && index.column() == 2) { 87 | QFont font; 88 | font.setUnderline(true); 89 | return font; 90 | } else if (role == Qt::ForegroundRole && index.column() == 2) { 91 | return QColor(Qt::darkBlue); 92 | } 93 | 94 | return QVariant(); 95 | } 96 | 97 | Qt::ItemFlags ServersTableModel::flags(const QModelIndex& index) const 98 | { 99 | Qt::ItemFlags res = Qt::NoItemFlags; 100 | 101 | switch ( index.column() ) 102 | { 103 | case 0: 104 | res |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled; 105 | break; 106 | case 1: 107 | res |= Qt::ItemIsEnabled; 108 | case 2: 109 | res |= Qt::ItemIsEnabled | Qt::ItemIsSelectable; 110 | break; 111 | } 112 | return res; 113 | } 114 | 115 | QVariant ServersTableModel::headerData(int section, Qt::Orientation orientation, int role) const 116 | { 117 | if ( role != Qt::DisplayRole || orientation != Qt::Horizontal ) 118 | return QVariant(); 119 | 120 | switch (section) 121 | { 122 | case 0: return QString("Active"); 123 | case 1: return QString("Name"); 124 | case 2: return QString("Website"); 125 | case 3: return QString("IP Address"); 126 | case 4: return QString("TLS Auth Name"); 127 | case 5: return QString("Pin (Key Digest Value)"); 128 | } 129 | 130 | return QVariant(""); 131 | } 132 | 133 | bool ServersTableModel::setData(const QModelIndex &index, const QVariant &value, int role) 134 | { 135 | if ( !index.isValid() ) 136 | return false; 137 | 138 | int serverIndex, addressIndex; 139 | serverFromRow(index.row(), serverIndex, addressIndex); 140 | 141 | if ( serverIndex < 0 ) 142 | return false; 143 | 144 | if ( index.column() == 0 && role == Qt::CheckStateRole ) 145 | { 146 | Config::Server& server(m_config.servers[serverIndex]); 147 | if ( static_cast(value.toInt()) == Qt::Checked ) 148 | server.inactive.erase(m_networkProfile); 149 | else 150 | server.inactive.insert(m_networkProfile); 151 | 152 | // All rows for this server have changed. 153 | int startRow = index.row() - addressIndex; 154 | int endRow = startRow + static_cast(server.addresses.size()) - 1; 155 | emit(dataChanged(index.siblingAtRow(startRow), index.siblingAtRow(endRow))); 156 | return true; 157 | } 158 | 159 | return false; 160 | } 161 | 162 | void ServersTableModel::STPConfigChanged() 163 | { 164 | beginResetModel(); 165 | endResetModel(); 166 | } 167 | 168 | void ServersTableModel::serverFromRow(int row, int& serverIndex, int& addressIndex) const 169 | { 170 | serverIndex = 0; 171 | addressIndex = 0; 172 | bool found = false; 173 | 174 | for ( auto& s : m_config.servers ) 175 | { 176 | if ( s.hidden.find(m_networkProfile) == s.hidden.end() ) 177 | { 178 | addressIndex = 0; 179 | for ( auto& a : s.addresses ) 180 | { 181 | if ( row == 0 ) 182 | { 183 | found = true; 184 | break; 185 | } 186 | 187 | --row; 188 | ++addressIndex; 189 | } 190 | 191 | if ( found ) 192 | break; 193 | } 194 | ++serverIndex; 195 | } 196 | 197 | if ( !found ) 198 | { 199 | serverIndex = -1; 200 | addressIndex = -1; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /serverstablemodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef PROFILESERVERSTABLEMODEL_H 10 | #define PROFILESERVERSTABLEMODEL_H 11 | 12 | #include 13 | 14 | #include "configmanager.h" 15 | 16 | class ServersTableModel : public QAbstractTableModel 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | ServersTableModel(Config& config, Config::NetworkProfile networkProfile, QObject* parent = NULL); 22 | virtual ~ServersTableModel(); 23 | 24 | int rowCount(const QModelIndex& parent = QModelIndex()) const; 25 | int columnCount(const QModelIndex& parent = QModelIndex()) const; 26 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; 27 | Qt::ItemFlags flags(const QModelIndex& index) const; 28 | QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 29 | 30 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); 31 | 32 | void STPConfigChanged(); 33 | 34 | private: 35 | void serverFromRow(int row, int& serverIndex, int& addressIndex) const; 36 | 37 | Config& m_config; 38 | Config::NetworkProfile m_networkProfile; 39 | }; 40 | 41 | #endif 42 | 43 | /* Local Variables: */ 44 | /* mode: c++ */ 45 | /* End: */ 46 | -------------------------------------------------------------------------------- /servicemanager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "mainwindow.h" 16 | 17 | 18 | ServiceMgr::ServiceMgr(MainWindow *parent) : 19 | QObject(parent), 20 | m_mainwindow(parent), 21 | m_serviceState(ServiceMgr::Unknown) 22 | { 23 | qInfo("Creating service mgr"); 24 | 25 | } 26 | 27 | ServiceMgr::~ServiceMgr() 28 | { 29 | } 30 | 31 | int ServiceMgr::getState() { 32 | //qInfo("gettting state"); 33 | return getStateofService(); 34 | } 35 | 36 | int ServiceMgr::start(ConfigMgr& configMgr) 37 | { 38 | QString message = "Action: Starting Stubby service wtih "; 39 | message.append(configMgr.getCurrentProfileString().c_str()); 40 | message.append(" profile..."); 41 | m_mainwindow->statusMsg(message); 42 | try { 43 | std::string stubby_yml = configMgr.generateStubbyConfig(); 44 | if (stubby_yml.empty()) { 45 | m_mainwindow->statusMsg("ERROR: Configuration generated for the active profile was invalid. Stubby has not been restarted."); 46 | return 1; 47 | } 48 | m_mainwindow->statusMsg("Status: Stubby service configuration generated."); 49 | m_serviceState = Starting; 50 | return startService(QString::fromStdString(stubby_yml)); 51 | } 52 | catch(const std::runtime_error& err) 53 | { 54 | qCritical("Error: %s", err.what()); 55 | return 1; 56 | } 57 | } 58 | 59 | int ServiceMgr::stop() 60 | { 61 | m_mainwindow->statusMsg("Action: Stopping Stubby service..."); 62 | m_serviceState = Stopping; 63 | return stopService(); 64 | } 65 | 66 | int ServiceMgr::restart() 67 | { 68 | m_mainwindow->statusMsg("Action: Re-starting Stubby service..."); 69 | m_serviceState = Restarting; 70 | return restartService(); 71 | } 72 | -------------------------------------------------------------------------------- /servicemanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Sinodun Internet Technologies Ltd. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, you can obtain one at https://mozilla.org/MPL/2.0/. 7 | */ 8 | 9 | #ifndef SERVICEMGR_H 10 | #define SERVICEMGR_H 11 | 12 | #include 13 | 14 | #include "config.h" 15 | 16 | class MainWindow; 17 | 18 | 19 | class ServiceMgr : public QObject 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | ServiceMgr(MainWindow *parent); 25 | virtual ~ServiceMgr(); 26 | 27 | static ServiceMgr * factory(MainWindow *parent); 28 | 29 | typedef enum { 30 | Stopped, 31 | Starting, 32 | Restarting, 33 | Running, 34 | Stopping, 35 | Unknown, 36 | Error 37 | } ServiceState; 38 | 39 | int getState(); 40 | int start(ConfigMgr& config); 41 | int stop(); 42 | int restart(); 43 | 44 | signals: 45 | void serviceStateChanged(ServiceMgr::ServiceState state); 46 | 47 | protected: 48 | MainWindow *m_mainwindow; 49 | ServiceState m_serviceState; 50 | 51 | private: 52 | virtual int getStateofService() = 0; 53 | virtual int startService(QString configfile = "", int loglevel = 6) = 0; 54 | virtual int stopService() = 0; 55 | virtual int restartService() = 0; 56 | 57 | }; 58 | 59 | #endif // SERVICEMGR_H 60 | -------------------------------------------------------------------------------- /stubby.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/stubby@245x145.png 4 | images/on.png 5 | images/off.png 6 | images/getdns_logo.png 7 | images/stubby.ico 8 | images/stubby@245x145_green.png 9 | images/stubby@245x145_red.png 10 | 11 | 12 | -------------------------------------------------------------------------------- /stubbytemplate.yml: -------------------------------------------------------------------------------- 1 | resolution_type: GETDNS_RESOLUTION_STUB 2 | dns_transport_list: {{TRANSPORT_LIST}} 3 | tls_authentication: {{AUTHENTICATION}} 4 | tls_query_padding_blocksize: 128 5 | edns_client_subnet_private : 1 6 | round_robin_upstreams: {{ROUND_ROBIN}} 7 | dnssec: {{DNSSEC}} 8 | idle_timeout: 10000 9 | listen_addresses: 10 | - 127.0.0.1 11 | - 0::1 12 | upstream_recursive_servers: 13 | {{#SERVER}} 14 | - address_data: {{SERVER_ADDRESS}} 15 | {{#AUTHNAME}} 16 | tls_auth_name: "{{SERVER_AUTH_NAME}}" 17 | {{/AUTHNAME}} 18 | {{#PINSET}} 19 | tls_pubkey_pinset: 20 | - digest: "{{SERVER_DIGEST_TYPE}}" 21 | value: {{SERVER_DIGEST_VALUE}} 22 | {{/PINSET}} 23 | {{/SERVER}} 24 | -------------------------------------------------------------------------------- /utils/env-debug.bat: -------------------------------------------------------------------------------- 1 | set Qt5_DIR=C:\Qt\5.15.0\msvc2019_64\lib\cmake\Qt5 2 | set Poco_DIR=C:\vcpkg\installed\x64-windows\share\poco 3 | set yaml-cpp_DIR=C:\vcpkg\installed\x64-windows\share\yaml-cpp 4 | set PATH=%PATH%;C:\Qt\5.15.0\msvc2019_64\bin;C:\vcpkg\installed\x64-windows\debug\bin 5 | -------------------------------------------------------------------------------- /utils/env-release.bat: -------------------------------------------------------------------------------- 1 | set Qt5_DIR=C:\Qt\5.15.0\msvc2019_64\lib\cmake\Qt5 2 | set Poco_DIR=C:\vcpkg\installed\x64-windows\share\poco 3 | set yaml-cpp_DIR=C:\vcpkg\installed\x64-windows\share\yaml-cpp 4 | set PATH=%PATH%;C:\Qt\5.15.0\msvc2019_64\bin;C:\vcpkg\installed\x64-windows\bin 5 | --------------------------------------------------------------------------------