From 437c90b6bf6371e347ca187c14495aaebc71b664 Mon Sep 17 00:00:00 2001 From: Ludvig Strigeus Date: Tue, 11 Sep 2018 21:10:10 +0200 Subject: [PATCH] Change Kill Switch behavior --- TunSafe.rc | 4 +- installer/ChangeLog.txt | 7 +++ network_win32.cpp | 108 +++++++++++++++++++++---------------- network_win32_dnsblock.cpp | 34 ++---------- network_win32_dnsblock.h | 16 ++---- resource.h | 4 +- tunsafe_win32.cpp | 22 ++++---- wireguard.h | 10 ++-- 8 files changed, 102 insertions(+), 103 deletions(-) diff --git a/TunSafe.rc b/TunSafe.rc index 55f2de5..42bc75c 100644 --- a/TunSafe.rc +++ b/TunSafe.rc @@ -18,6 +18,7 @@ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) LANGUAGE LANG_SWEDISH, SUBLANG_SWEDISH +#pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -160,10 +161,11 @@ BEGIN POPUP "Internet &Kill Switch" BEGIN MENUITEM "&Off", IDSETT_BLOCKINTERNET_OFF - MENUITEM SEPARATOR MENUITEM "Yes, with &Routing Rules", IDSETT_BLOCKINTERNET_ROUTE MENUITEM "Yes, with &Firewall Rules", IDSETT_BLOCKINTERNET_FIREWALL MENUITEM "Yes, &Both Methods", IDSETT_BLOCKINTERNET_BOTH + MENUITEM SEPARATOR + MENUITEM "Block While &Disconnected", IDSETT_BLOCKINTERNET_DISCONN END POPUP "&Service Mode" BEGIN diff --git a/installer/ChangeLog.txt b/installer/ChangeLog.txt index f3b5b91..083a904 100644 --- a/installer/ChangeLog.txt +++ b/installer/ChangeLog.txt @@ -1,3 +1,10 @@ +2018-??-?? - TunSafe v1.4-rc2 + +Changes: +1.The kill switch is now remembered across computer restarts and + is deactivated when disconnecting. Without this behavior, the + kill switch is unusable when auto connecting on Windows startup. + 2018-08-11 - TunSafe v1.4-rc1 Changes: diff --git a/network_win32.cpp b/network_win32.cpp index fbef442..2b9c680 100644 --- a/network_win32.cpp +++ b/network_win32.cpp @@ -20,6 +20,7 @@ #include "util.h" #include #include "network_win32_dnsblock.h" +#include "util_win32.h" enum { HARD_MAXIMUM_QUEUE_SIZE = 102400, @@ -27,13 +28,6 @@ enum { MAX_BYTES_IN_UDP_OUT_QUEUE_SMALL = (256 + 64) * 1024, }; -enum { - ROUTE_BLOCK_UNKNOWN = 0, - ROUTE_BLOCK_OFF = 1, - ROUTE_BLOCK_ON = 2, - ROUTE_BLOCK_PENDING = 3, -}; - enum { kMetricNone = -1, kMetricAutomatic = 0, @@ -41,10 +35,13 @@ enum { static uint8 internet_route_blocking_state; static SLIST_HEADER freelist_head; +static HKEY g_hklm_reg_key; +static uint8 g_killswitch_curr = 255, g_killswitch_want; bool g_allow_pre_post; static InternetBlockState GetInternetBlockState(bool *is_activated); +static void DeactivateKillSwitch(InternetBlockState want); Packet *AllocPacket() { Packet *packet = (Packet*)InterlockedPopEntrySList(&freelist_head); @@ -899,7 +896,6 @@ void ThreadedPacketQueue::Stop() { CloseHandle(handle_); handle_ = NULL; } - } void ThreadedPacketQueue::AbortingDriver() { @@ -1288,10 +1284,13 @@ bool TunWin32Adapter::InitAdapter(const TunInterface::TunConfig &&config, TunInt } else { dns_blocker_->RestoreDns(); } + + // Cache the state of internet blocking + GetInternetBlockState(NULL); uint8 ibs = config.internet_blocking; if (ibs == kBlockInternet_Default || ibs == kBlockInternet_DefaultOn) { - uint8 new_ibs = GetInternetBlockState(NULL); + uint8 new_ibs = (g_killswitch_want & (kBlockInternet_Firewall | kBlockInternet_Route)); ibs = (new_ibs == kBlockInternet_Off && ibs == kBlockInternet_DefaultOn) ? kBlockInternet_Firewall : new_ibs; } @@ -1331,18 +1330,18 @@ bool TunWin32Adapter::InitAdapter(const TunInterface::TunConfig &&config, TunInt if (!AddMultipleCatchallRoutes(AF_INET6, 1, (uint8*)&dst, localhost_luid, NULL)) RERROR("Unable to add IPv6 routes for route based blocking."); } + g_killswitch_curr |= kBlockInternet_Route; } } - internet_route_blocking_state = block_all_traffic_route + ROUTE_BLOCK_OFF; - if (ibs & kBlockInternet_Firewall) { - RINFO("Blocking all regular Internet traffic%s", ri.found_default_adapter ? " (except DHCP)" : ""); - AddPersistentInternetBlocking(ri.found_default_adapter ? &ri.default_adapter : NULL, interface_luid_, config.ipv6_cidr != 0); - } else { - SetInternetFwBlockingState(false); + RINFO("Blocking all regular Internet traffic using firewall rules"); + if (AddKillSwitchFirewall(ri.found_default_adapter ? &ri.default_adapter : NULL, interface_luid_, config.ipv6_cidr != 0)) + g_killswitch_curr |= kBlockInternet_Firewall; } + DeactivateKillSwitch((InternetBlockState)ibs); + // Configure default route? if (config.use_ipv4_default_route) { // Add a bypass route to the original gateway? @@ -2040,8 +2039,10 @@ TunsafeBackendWin32::TunsafeBackendWin32(Delegate *delegate) : delegate_(delegat last_tun_adapter_failed_ = 0; want_periodic_stats_ = false; - internet_route_blocking_state = ROUTE_BLOCK_UNKNOWN; - ClearInternetFwBlockingStateCache(); + if (g_hklm_reg_key == NULL) { + RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\TunSafe", NULL, NULL, 0, KEY_ALL_ACCESS, NULL, &g_hklm_reg_key, NULL); + g_killswitch_want = RegReadInt(g_hklm_reg_key, "KillSwitch", 0); + } delegate_->OnStateChanged(); } @@ -2115,6 +2116,9 @@ void TunsafeBackendWin32::StopInner(bool is_restart) { config_file_ = NULL; is_started_ = false; status_ = kStatusStopped; + + if (!is_restart && !(g_killswitch_want & kBlockInternet_BlockOnDisconnect)) + DeactivateKillSwitch(kBlockInternet_Off); } } @@ -2149,46 +2153,60 @@ LinearizedGraph *TunsafeBackendWin32::GetGraph(int type) { return graph; } - -static uint8 GetInternetRouteBlockingState() { - if (internet_route_blocking_state == ROUTE_BLOCK_UNKNOWN) { - RouteInfo ri; - internet_route_blocking_state = - (GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, TRUE, NULL, &ri) && ri.found_null_routes == 2) + ROUTE_BLOCK_OFF; - } - return internet_route_blocking_state; +static bool GetKillSwitchRouteActive() { + RouteInfo ri; + return (GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, TRUE, NULL, &ri) && ri.found_null_routes == 2); } -static void SetInternetRouteBlockingState(bool want) { - if (want) { - internet_route_blocking_state = ROUTE_BLOCK_PENDING; - } else if (internet_route_blocking_state != ROUTE_BLOCK_OFF) { - RouteInfo ri; - GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, FALSE, NULL, &ri); - GetDefaultRouteAndDeleteOldRoutes(AF_INET6, NULL, FALSE, NULL, &ri); - internet_route_blocking_state = ROUTE_BLOCK_OFF; - } +static void RemoveKillSwitchRoute() { + RouteInfo ri; + GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, FALSE, NULL, &ri); + GetDefaultRouteAndDeleteOldRoutes(AF_INET6, NULL, FALSE, NULL, &ri); } static InternetBlockState GetInternetBlockState(bool *is_activated) { - int a = GetInternetRouteBlockingState(); - int b = GetInternetFwBlockingState(); - + // Read the value only once. + if (g_killswitch_curr == 255) { + g_killswitch_curr = GetKillSwitchRouteActive() * kBlockInternet_Route + + GetKillSwitchFirewallActive() * kBlockInternet_Firewall; + } if (is_activated) - *is_activated = (a == ROUTE_BLOCK_ON || b == IBS_ACTIVE); - - return (InternetBlockState)( - (a >= ROUTE_BLOCK_ON) * kBlockInternet_Route + - (b >= IBS_ACTIVE) * kBlockInternet_Firewall); + *is_activated = g_killswitch_curr != 0; + return (InternetBlockState)g_killswitch_want; } InternetBlockState TunsafeBackendWin32::GetInternetBlockState(bool *is_activated) { return ::GetInternetBlockState(is_activated); } -void TunsafeBackendWin32::SetInternetBlockState(InternetBlockState s) { - SetInternetRouteBlockingState((s & kBlockInternet_Route) != 0); - SetInternetFwBlockingState((s & kBlockInternet_Firewall) != 0); +static void DeactivateKillSwitch(InternetBlockState want) { + // Disable blocking without reconnecting + int maybeon = g_killswitch_curr | g_killswitch_want; + if ((maybeon & kBlockInternet_Route) > (want & kBlockInternet_Route)) { + if (g_killswitch_curr & kBlockInternet_Route) { + g_killswitch_curr &= ~kBlockInternet_Route; + RINFO("Removing the routing rule internet block"); + } + RemoveKillSwitchRoute(); + } + if ((maybeon & kBlockInternet_Firewall) > (want & kBlockInternet_Firewall)) { + if (g_killswitch_curr & kBlockInternet_Firewall) { + g_killswitch_curr &= ~kBlockInternet_Firewall; + RINFO("Removing the firewall internet block"); + } + RemoveKillSwitchFirewall(); + } +} + +void TunsafeBackendWin32::SetInternetBlockState(InternetBlockState want) { + GetInternetBlockState(NULL); // ensure cache is read + + if (worker_thread_ == NULL && !(want & kBlockInternet_BlockOnDisconnect)) + DeactivateKillSwitch(kBlockInternet_Off); + else + DeactivateKillSwitch(want); + g_killswitch_want = want; + RegWriteInt(g_hklm_reg_key, "KillSwitch", (int)want); } void TunsafeBackendWin32::SetServiceStartupFlags(uint32 flags) { diff --git a/network_win32_dnsblock.cpp b/network_win32_dnsblock.cpp index b76fb91..b6d3824 100644 --- a/network_win32_dnsblock.cpp +++ b/network_win32_dnsblock.cpp @@ -203,8 +203,6 @@ static bool RemovePersistentInternetBlockingInner(HANDLE handle) { goto getout; } - internet_fw_blocking_state = IBS_INACTIVE; - getout: if (enum_handle != NULL) { FwpmFilterDestroyEnumHandle0(handle, enum_handle); @@ -212,7 +210,7 @@ getout: return false; } -bool AddPersistentInternetBlocking(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6) { +bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6) { FWPM_SUBLAYER0 *sublayer_p = NULL; FWP_BYTE_BLOB *fwp_appid = NULL; FWPM_FILTER0 filter; @@ -312,7 +310,6 @@ bool AddPersistentInternetBlocking(const NET_LUID *default_interface, const NET_ goto getout; success = true; - internet_fw_blocking_state = IBS_ACTIVE; getout: if (handle != NULL) { @@ -327,7 +324,7 @@ getout: return success; } -static bool RemovePersistentInternetBlocking() { +void RemoveKillSwitchFirewall() { DWORD err; HANDLE handle = NULL; FWPM_SUBLAYER0 *sublayer_p = NULL; @@ -345,8 +342,6 @@ static bool RemovePersistentInternetBlocking() { // The sublayer exists FwpmFreeMemory0((void **)&sublayer_p); } else { - // Sublayer does not exist - internet_fw_blocking_state = IBS_INACTIVE; goto getout; } @@ -357,17 +352,9 @@ getout: FwpmEngineClose0(handle); handle = NULL; } - return false; } -void ClearInternetFwBlockingStateCache() { - internet_fw_blocking_state = 0; -} - -uint8 GetInternetFwBlockingState() { - if (internet_fw_blocking_state != 0) - return internet_fw_blocking_state; - +bool GetKillSwitchFirewallActive() { DWORD err; HANDLE handle = NULL; FWPM_SUBLAYER0 *sublayer_p = NULL; @@ -395,18 +382,5 @@ getout: FwpmEngineClose0(handle); handle = NULL; } - - return internet_fw_blocking_state = result + IBS_INACTIVE; + return result; } - -void SetInternetFwBlockingState(bool want) { - uint8 old_state = GetInternetFwBlockingState(); - if ((old_state >= IBS_ACTIVE) != want) { - if (!want) { - RemovePersistentInternetBlocking(); - } else { - internet_fw_blocking_state = IBS_PENDING; - } - } -} - diff --git a/network_win32_dnsblock.h b/network_win32_dnsblock.h index 3bc9c7f..0bcac80 100644 --- a/network_win32_dnsblock.h +++ b/network_win32_dnsblock.h @@ -18,16 +18,6 @@ public: bool also_ipv6_; }; - -bool AddPersistentInternetBlocking(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6); - -enum { - IBS_UNKOWN, - IBS_INACTIVE, - IBS_ACTIVE, - IBS_PENDING, -}; -void SetInternetFwBlockingState(bool want); -uint8 GetInternetFwBlockingState(); - -void ClearInternetFwBlockingStateCache(); \ No newline at end of file +bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6); +void RemoveKillSwitchFirewall(); +bool GetKillSwitchFirewallActive(); diff --git a/resource.h b/resource.h index 3e32567..a51f9bb 100644 --- a/resource.h +++ b/resource.h @@ -27,6 +27,7 @@ #define IDSETT_SERVICE_BACKGROUND 23 #define IDSETT_SERVICE_CONNECT_AUTO 24 #define IDSETT_SERVICE_MINIMIZE_AUTO 25 +#define IDSETT_BLOCKINTERNET_DISCONN 26 #define IDC_PAINTBOX 30 #define IDC_GRAPHBOX 31 #define IDC_ADVANCEDBOX 32 @@ -40,12 +41,13 @@ #define IDC_PUBLIC_KEY 109 #define IDC_TAB 110 + // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 113 -#define _APS_NEXT_COMMAND_VALUE 40023 +#define _APS_NEXT_COMMAND_VALUE 40026 #define _APS_NEXT_CONTROL_VALUE 1016 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/tunsafe_win32.cpp b/tunsafe_win32.cpp index e74a02b..96dba0e 100644 --- a/tunsafe_win32.cpp +++ b/tunsafe_win32.cpp @@ -123,7 +123,6 @@ static bool GetConfigFullName(const char *basename, char *fullname, size_t fulln return true; } - void StopTunsafeBackend(UpdateIconWhy why) { if (g_backend->is_started()) { g_backend->Stop(); @@ -916,20 +915,25 @@ static void HandleClickedItem(HWND hWnd, int wParam) { case IDSETT_BLOCKINTERNET_FIREWALL: case IDSETT_BLOCKINTERNET_BOTH: { - InternetBlockState old_state = g_backend->GetInternetBlockState(NULL); - InternetBlockState new_state = (InternetBlockState)(wParam - IDSETT_BLOCKINTERNET_OFF); + uint32 old_state = g_backend->GetInternetBlockState(NULL); + uint32 new_state = wParam - IDSETT_BLOCKINTERNET_OFF; - if (old_state == kBlockInternet_Off && new_state != kBlockInternet_Off) { - if (MessageBoxA(g_ui_window, "Warning! All Internet traffic will be blocked until you restart your computer. Only traffic through TunSafe will be allowed.\r\n\r\nThe blocking is activated the next time you connect to a VPN server.\r\n\r\nDo you want to continue?", "TunSafe", MB_ICONWARNING | MB_OKCANCEL) == IDCANCEL) + if ((old_state & kBlockInternet_Both) == kBlockInternet_Off && new_state != kBlockInternet_Off) { + if (MessageBoxA(g_ui_window, "Warning! All Internet traffic will be blocked while TunSafe is active. Only traffic through TunSafe will be allowed.\r\n\r\nThe blocking is activated the next time TunSafe connects.\r\n\r\nDo you want to continue?", "TunSafe", MB_ICONWARNING | MB_OKCANCEL) == IDCANCEL) return; } - - g_backend->SetInternetBlockState(new_state); + g_backend->SetInternetBlockState((InternetBlockState)(new_state | (old_state & kBlockInternet_BlockOnDisconnect))); if ((~old_state & new_state) && g_backend->is_started()) StartTunsafeBackend(UIW_START); return; } + case IDSETT_BLOCKINTERNET_DISCONN: { + uint32 old_state = g_backend->GetInternetBlockState(NULL); + g_backend->SetInternetBlockState((InternetBlockState)(old_state ^ kBlockInternet_BlockOnDisconnect)); + return; + } + case IDSETT_SERVICE_OFF: case IDSETT_SERVICE_FOREGROUND: case IDSETT_SERVICE_BACKGROUND: @@ -1034,9 +1038,9 @@ static INT_PTR WINAPI DlgProc(HWND hWnd, UINT message, WPARAM wParam, bool is_activated = false; int value = g_backend->GetInternetBlockState(&is_activated); - CheckMenuRadioItem(menu, IDSETT_BLOCKINTERNET_OFF, IDSETT_BLOCKINTERNET_BOTH, IDSETT_BLOCKINTERNET_OFF + value, MF_BYCOMMAND); + CheckMenuRadioItem(menu, IDSETT_BLOCKINTERNET_OFF, IDSETT_BLOCKINTERNET_BOTH, IDSETT_BLOCKINTERNET_OFF + (value & kBlockInternet_Both), MF_BYCOMMAND); CheckMenuRadioItem(menu, IDSETT_SERVICE_OFF, IDSETT_SERVICE_BACKGROUND, IDSETT_SERVICE_OFF + (g_startup_flags & 3), MF_BYCOMMAND); - + CheckMenuItem(menu, IDSETT_BLOCKINTERNET_DISCONN, (value & kBlockInternet_BlockOnDisconnect) ? MF_CHECKED : 0); break; } diff --git a/wireguard.h b/wireguard.h index 5831982..d357d41 100644 --- a/wireguard.h +++ b/wireguard.h @@ -52,10 +52,12 @@ public: }; enum InternetBlockState { - kBlockInternet_Off, - kBlockInternet_Route, - kBlockInternet_Firewall, - kBlockInternet_Both, + kBlockInternet_Off = 0, + kBlockInternet_Route = 1, + kBlockInternet_Firewall = 2, + kBlockInternet_Both = 3, + + kBlockInternet_BlockOnDisconnect = 16, // An unspecified value that uses either route or firewall kBlockInternet_DefaultOn = 254,