From 358c79a9186f31455e8c5f0dd568290393610539 Mon Sep 17 00:00:00 2001 From: Ludvig Strigeus Date: Sun, 21 Oct 2018 21:53:02 +0200 Subject: [PATCH] Improve killswitch behavior on Win32. Now there exists a button for it. --- TunSafe.rc | 4 +- network_win32.cpp | 108 ++++++++++++++++++------------------- network_win32.h | 4 +- network_win32_api.h | 3 +- network_win32_dnsblock.cpp | 102 ++++++++++++++++++++++++----------- network_win32_dnsblock.h | 2 +- resource.h | 5 +- service_win32.cpp | 17 +++--- service_win32.h | 8 +-- service_win32_constants.h | 2 +- tunsafe_win32.cpp | 32 ++++++++--- wireguard.h | 7 +-- wireguard_config.cpp | 21 +++++--- 13 files changed, 190 insertions(+), 125 deletions(-) diff --git a/TunSafe.rc b/TunSafe.rc index 42bc75c..4bdb3ed 100644 --- a/TunSafe.rc +++ b/TunSafe.rc @@ -60,10 +60,11 @@ BEGIN PUSHBUTTON "&Connect",ID_START,247,3,50,14 PUSHBUTTON "&Disconnect",ID_STOP,247,19,50,14 PUSHBUTTON "&Edit Config",ID_EDITCONF,247,35,50,14 + PUSHBUTTON "Turn Off &Kill Switch",ID_BTN_KILLSWITCH,154,19,90,14,WS_CLIPSIBLINGS CONTROL "",IDC_RICHEDIT21,"RichEdit20A",ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP,167,180,40,16 CONTROL "",IDC_ADVANCEDBOX,"AdvancedBox",0x0,105,181,35,15 CONTROL "",IDC_GRAPHBOX,"GraphBox",0x0,239,181,35,15 - CONTROL "",IDC_PAINTBOX,"PaintBox",0x0,4,0,240,44 + CONTROL "",IDC_PAINTBOX,"PaintBox",0x0,4,0,240,44,0x4000000L CONTROL "",IDC_TAB,"SysTabControl32",WS_TABSTOP,4,49,293,122 END @@ -166,6 +167,7 @@ BEGIN MENUITEM "Yes, &Both Methods", IDSETT_BLOCKINTERNET_BOTH MENUITEM SEPARATOR MENUITEM "Block While &Disconnected", IDSETT_BLOCKINTERNET_DISCONN + MENUITEM "Allow Traffic to &Local Networks", IDSETT_BLOCKINTERNET_ALLOWLOCAL END POPUP "&Service Mode" BEGIN diff --git a/network_win32.cpp b/network_win32.cpp index b364c6c..45da5ee 100644 --- a/network_win32.cpp +++ b/network_win32.cpp @@ -36,12 +36,11 @@ 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; +static uint8 g_killswitch_curr, g_killswitch_want, g_killswitch_currconn; bool g_allow_pre_post; -static InternetBlockState GetInternetBlockState(bool *is_activated); -static void DeactivateKillSwitch(InternetBlockState want); +static void DeactivateKillSwitch(uint32 want); Packet *AllocPacket() { Packet *packet = (Packet*)InterlockedPopEntrySList(&freelist_head); @@ -1280,15 +1279,9 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T 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 = (g_killswitch_want & (kBlockInternet_Firewall | kBlockInternet_Route)); - ibs = (new_ibs == kBlockInternet_Off && ibs == kBlockInternet_DefaultOn) ? kBlockInternet_Firewall : new_ibs; - } - + g_killswitch_currconn = config.internet_blocking; + uint8 ibs = (g_killswitch_currconn == kBlockInternet_Default) ? g_killswitch_want : g_killswitch_currconn; + bool block_all_traffic_route = (ibs & kBlockInternet_Route) != 0; RouteInfo ri, ri6; @@ -1318,24 +1311,36 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T if (ConvertInterfaceIndexToLuid(1, &localhost_luid) || localhost_luid.Info.IfType != 24) { RERROR("Unable to get localhost luid - while adding route based blocking."); } else { - uint32 dst[4] = {0}; - if (!AddMultipleCatchallRoutes(AF_INET, 1, (uint8*)&dst, localhost_luid, NULL)) - RERROR("Unable to add routes for route based blocking."); - if (config.ipv6_cidr) { - 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; + + uint32 dst[4] = {0}; + if (!AddMultipleCatchallRoutes(AF_INET, 1, (uint8*)&dst, localhost_luid, NULL)) { + RERROR("Unable to add routes for route based blocking."); + DeactivateKillSwitch(0); + return false; + } + if (config.ipv6_cidr) { + if (!AddMultipleCatchallRoutes(AF_INET6, 1, (uint8*)&dst, localhost_luid, NULL)) { + RERROR("Unable to add IPv6 routes for route based blocking."); + DeactivateKillSwitch(0); + return false; + } + } } } if (ibs & kBlockInternet_Firewall) { 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; + g_killswitch_curr |= kBlockInternet_Firewall; + + if (!AddKillSwitchFirewall(interface_luid_, config.ipv6_cidr != 0, (ibs & kBlockInternet_AllowLocalNetworks) != 0)) { + RERROR("Unable to activate firewall based kill switch"); + DeactivateKillSwitch(0); + return false; + } } - DeactivateKillSwitch((InternetBlockState)ibs); + DeactivateKillSwitch(ibs); // Configure default route? if (config.use_ipv4_default_route) { @@ -2018,6 +2023,17 @@ TunsafeBackend::~TunsafeBackend() { } +static bool GetKillSwitchRouteActive() { + RouteInfo ri; + return (GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, TRUE, NULL, &ri) && ri.found_null_routes == 2); +} + +static void RemoveKillSwitchRoute() { + RouteInfo ri; + GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, FALSE, NULL, &ri); + GetDefaultRouteAndDeleteOldRoutes(AF_INET6, NULL, FALSE, NULL, &ri); +} + TunsafeBackendWin32::TunsafeBackendWin32(Delegate *delegate) : delegate_(delegate), dns_resolver_(&dns_blocker_) { memset(&stats_, 0, sizeof(stats_)); wg_processor_ = NULL; @@ -2029,6 +2045,8 @@ TunsafeBackendWin32::TunsafeBackendWin32(Delegate *delegate) : delegate_(delegat 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); + g_killswitch_curr = GetKillSwitchRouteActive() * kBlockInternet_Route + + GetKillSwitchFirewallActive() * kBlockInternet_Firewall; } delegate_->OnStateChanged(); } @@ -2089,6 +2107,7 @@ void TunsafeBackendWin32::Stop() { void TunsafeBackendWin32::Start(const char *config_file) { StopInner(true); dns_resolver_.ResetCancel(); + g_killswitch_currconn = kBlockInternet_Default; is_started_ = true; memset(public_key_, 0, sizeof(public_key_)); SetStatus(kStatusInitializing); @@ -2118,7 +2137,8 @@ void TunsafeBackendWin32::StopInner(bool is_restart) { status_ = kStatusStopped; packet_processor_.Reset(); - if (!is_restart && !(g_killswitch_want & kBlockInternet_BlockOnDisconnect)) + uint8 wanted_ibs = (g_killswitch_currconn == kBlockInternet_Default) ? g_killswitch_want : g_killswitch_currconn; + if (!is_restart && !(wanted_ibs & kBlockInternet_BlockOnDisconnect)) DeactivateKillSwitch(kBlockInternet_Off); } } @@ -2154,35 +2174,13 @@ LinearizedGraph *TunsafeBackendWin32::GetGraph(int type) { return graph; } -static bool GetKillSwitchRouteActive() { - RouteInfo ri; - return (GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, TRUE, NULL, &ri) && ri.found_null_routes == 2); +InternetBlockState TunsafeBackendWin32::GetInternetBlockState() { + return (InternetBlockState)(g_killswitch_want | (g_killswitch_curr ? kBlockInternet_Active : 0)); } -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) { - // Read the value only once. - if (g_killswitch_curr == 255) { - g_killswitch_curr = GetKillSwitchRouteActive() * kBlockInternet_Route + - GetKillSwitchFirewallActive() * kBlockInternet_Firewall; - } - if (is_activated) - *is_activated = g_killswitch_curr != 0; - return (InternetBlockState)g_killswitch_want; -} - -InternetBlockState TunsafeBackendWin32::GetInternetBlockState(bool *is_activated) { - return ::GetInternetBlockState(is_activated); -} - -static void DeactivateKillSwitch(InternetBlockState want) { +static void DeactivateKillSwitch(uint32 want) { // Disable blocking without reconnecting - int maybeon = g_killswitch_curr | g_killswitch_want; + uint32 maybeon = g_killswitch_curr; if ((maybeon & kBlockInternet_Route) > (want & kBlockInternet_Route)) { if (g_killswitch_curr & kBlockInternet_Route) { g_killswitch_curr &= ~kBlockInternet_Route; @@ -2200,14 +2198,16 @@ static void DeactivateKillSwitch(InternetBlockState want) { } void TunsafeBackendWin32::SetInternetBlockState(InternetBlockState want) { - GetInternetBlockState(NULL); // ensure cache is read - - if (worker_thread_ == NULL && !(want & kBlockInternet_BlockOnDisconnect)) + if (worker_thread_ == NULL && !(want & kBlockInternet_BlockOnDisconnect) || !(want & kBlockInternet_Active)) DeactivateKillSwitch(kBlockInternet_Off); else DeactivateKillSwitch(want); - g_killswitch_want = want; - RegWriteInt(g_hklm_reg_key, "KillSwitch", (int)want); + + int value = want & 0xff; + g_killswitch_want = value; + RegWriteInt(g_hklm_reg_key, "KillSwitch", (int)value); + + delegate_->OnStateChanged(); } void TunsafeBackendWin32::SetServiceStartupFlags(uint32 flags) { diff --git a/network_win32.h b/network_win32.h index 10532a4..a75447f 100644 --- a/network_win32.h +++ b/network_win32.h @@ -218,7 +218,7 @@ public: virtual void Stop() override; virtual void RequestStats(bool enable) override; virtual void ResetStats() override; - virtual InternetBlockState GetInternetBlockState(bool *is_activated) override; + virtual InternetBlockState GetInternetBlockState() override; virtual void SetInternetBlockState(InternetBlockState s) override; virtual void SetServiceStartupFlags(uint32 flags) override; virtual LinearizedGraph *GetGraph(int type) override; @@ -248,7 +248,7 @@ private: HANDLE worker_thread_; bool want_periodic_stats_; - + Delegate *delegate_; char *config_file_; diff --git a/network_win32_api.h b/network_win32_api.h index b280997..aaff158 100644 --- a/network_win32_api.h +++ b/network_win32_api.h @@ -97,8 +97,9 @@ public: virtual void RequestStats(bool enable) = 0; virtual void ResetStats() = 0; - virtual InternetBlockState GetInternetBlockState(bool *is_activated) = 0; + virtual InternetBlockState GetInternetBlockState() = 0; virtual void SetInternetBlockState(InternetBlockState s) = 0; + virtual void SetServiceStartupFlags(uint32 flags) = 0; virtual std::string GetConfigFileName() = 0; virtual LinearizedGraph *GetGraph(int type) = 0; diff --git a/network_win32_dnsblock.cpp b/network_win32_dnsblock.cpp index b6d3824..a0e4f1d 100644 --- a/network_win32_dnsblock.cpp +++ b/network_win32_dnsblock.cpp @@ -159,7 +159,7 @@ void DnsBlocker::RestoreDns() { } } -static bool RemovePersistentInternetBlockingInner(HANDLE handle) { +static bool RemovePersistentInternetBlockingInner(HANDLE handle, bool destroy_sublayer) { FWPM_FILTER_ENUM_TEMPLATE0 enum_template = {0}; HANDLE enum_handle = NULL; DWORD err; @@ -184,7 +184,7 @@ static bool RemovePersistentInternetBlockingInner(HANDLE handle) { } for (UINT32 i = 0; i < num_returned; i++) { FWPM_FILTER0 *cur_filter = filter[i]; - if (memcmp(&cur_filter->subLayerKey, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER, sizeof(GUID)) == 0) { + if (memcmp(&cur_filter->subLayerKey, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER, sizeof(GUID)) == 0 && (destroy_sublayer || cur_filter->numFilterConditions != 0)) { err = FwpmFilterDeleteById0(handle, cur_filter->filterId); if (err != 0) RERROR("FwpmFilterDeleteById0 failed: %d", err); @@ -197,10 +197,12 @@ static bool RemovePersistentInternetBlockingInner(HANDLE handle) { enum_handle = NULL; } - err = FwpmSubLayerDeleteByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER); - if (err != 0 && err != FWP_E_SUBLAYER_NOT_FOUND) { - RERROR("FwpmSubLayerDeleteByKey0 failed: %d", err); - goto getout; + if (destroy_sublayer) { + err = FwpmSubLayerDeleteByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER); + if (err != 0 && err != FWP_E_SUBLAYER_NOT_FOUND) { + RERROR("FwpmSubLayerDeleteByKey0 failed: %d", err); + goto getout; + } } getout: @@ -210,7 +212,16 @@ getout: return false; } -bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6) { +struct LastKillswitchSettings { + NET_LUID luid_to_allow; + bool also_ipv6; + bool allow_local_networks; +}; + +static LastKillswitchSettings last_killswitch_settings; + + +bool AddKillSwitchFirewall(const NET_LUID &luid_to_allow, bool also_ipv6, bool allow_local_networks) { FWPM_SUBLAYER0 *sublayer_p = NULL; FWP_BYTE_BLOB *fwp_appid = NULL; FWPM_FILTER0 filter; @@ -219,6 +230,11 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu HANDLE handle = NULL; bool success = false; + LastKillswitchSettings new_settings; + new_settings.luid_to_allow = luid_to_allow; + new_settings.also_ipv6 = also_ipv6; + new_settings.allow_local_networks = allow_local_networks; + { FWPM_SESSION0 session = {0}; err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &handle); @@ -231,6 +247,9 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu if (FwpmSubLayerGetByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER, &sublayer_p) == 0) { // The sublayer already exists FwpmFreeMemory0((void **)&sublayer_p); + + if (memcmp(&last_killswitch_settings, &new_settings, sizeof(new_settings)) != 0) + RemovePersistentInternetBlockingInner(handle, false); } else { // Add new sublayer FWPM_SUBLAYER0 sublayer = {0}; @@ -273,49 +292,72 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu filter.weight.uint8 = 14; if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) goto getout; + // Permit everything that's loopback filter_condition[0].fieldKey = FWPM_CONDITION_INTERFACE_TYPE; filter_condition[0].conditionValue.type = FWP_UINT32; filter_condition[0].conditionValue.uint32 = 24; filter_condition[0].matchType = FWP_MATCH_EQUAL; filter.weight.uint8 = 13; - if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) + if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 3)) goto getout; - // Permit all queries on the DHCP port (It uses 68 on the local side and 67 on the remote side) - if (default_interface) { - filter_condition[2].fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; - filter_condition[2].matchType = FWP_MATCH_EQUAL; - filter_condition[2].conditionValue.type = FWP_UINT16; - filter_condition[2].conditionValue.uint16 = 68; - filter_condition[1].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; - filter_condition[1].matchType = FWP_MATCH_EQUAL; - filter_condition[1].conditionValue.type = FWP_UINT16; - filter_condition[1].conditionValue.uint16 = 67; - filter.numFilterConditions = 3; - filter_condition[0].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; - filter_condition[0].conditionValue.type = FWP_UINT64; - filter_condition[0].conditionValue.uint64 = (uint64*)&default_interface->Value; - filter_condition[0].matchType = FWP_MATCH_EQUAL; - filter.weight.uint8 = 12; - if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) - goto getout; + // Permit everything going out to local networks + // '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16' + if (allow_local_networks) { + static const FWP_V4_ADDR_AND_MASK kLocalNetworkAddrMask[3] = { + {0x0A000000, 0xff000000}, // 10.0.0.0/8 + {0xAC100000, 0xfff00000}, // 172.16.0.0/12 + {0xC0A80000, 0xffff0000}, // 192.168.0.0/16 + }; + for (int i = 0; i < 3; i++) { + FWP_V4_ADDR_AND_MASK addr_mask = kLocalNetworkAddrMask[i]; + filter.numFilterConditions = 1; + filter_condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS; + filter_condition[0].conditionValue.type = FWP_V4_ADDR_MASK; + filter_condition[0].conditionValue.v4AddrMask = &addr_mask; + filter_condition[0].matchType = FWP_MATCH_EQUAL; + filter.weight.uint8 = 12; + if (!FwpmFilterAddCheckedAleConnect(handle, &filter, false, 4)) + goto getout; + } } + // Permit all queries on the DHCP port (It uses 68 on the local side and 67 on the remote side) + filter_condition[2].fieldKey = FWPM_CONDITION_IP_LOCAL_PORT; + filter_condition[2].matchType = FWP_MATCH_EQUAL; + filter_condition[2].conditionValue.type = FWP_UINT16; + filter_condition[2].conditionValue.uint16 = 68; + filter_condition[1].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + filter_condition[1].matchType = FWP_MATCH_EQUAL; + filter_condition[1].conditionValue.type = FWP_UINT16; + filter_condition[1].conditionValue.uint16 = 67; + filter.numFilterConditions = 3; + filter_condition[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL; + filter_condition[0].conditionValue.type = FWP_UINT8; + filter_condition[0].conditionValue.uint8 = 17; // UDP + filter_condition[0].matchType = FWP_MATCH_EQUAL; + filter.weight.uint8 = 12; + if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 5)) + goto getout; + // Block the rest filter.numFilterConditions = 0; filter.weight.type = FWP_EMPTY; filter.action.type = FWP_ACTION_BLOCK; - if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 3)) + if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 6)) goto getout; success = true; + last_killswitch_settings = new_settings; getout: + if (!success) + memset(&last_killswitch_settings, 0, sizeof(last_killswitch_settings)); + if (handle != NULL) { - // delete the layer on failure if (!success) - RemovePersistentInternetBlockingInner(handle); + RemovePersistentInternetBlockingInner(handle, true); FwpmEngineClose0(handle); handle = NULL; } @@ -345,7 +387,7 @@ void RemoveKillSwitchFirewall() { goto getout; } - RemovePersistentInternetBlockingInner(handle); + RemovePersistentInternetBlockingInner(handle, true); getout: if (handle != NULL) { diff --git a/network_win32_dnsblock.h b/network_win32_dnsblock.h index 0bcac80..fa35a98 100644 --- a/network_win32_dnsblock.h +++ b/network_win32_dnsblock.h @@ -18,6 +18,6 @@ public: bool also_ipv6_; }; -bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6); +bool AddKillSwitchFirewall(const NET_LUID &luid_to_allow, bool also_ipv6, bool allow_local_networks); void RemoveKillSwitchFirewall(); bool GetKillSwitchFirewallActive(); diff --git a/resource.h b/resource.h index a51f9bb..8979ce2 100644 --- a/resource.h +++ b/resource.h @@ -28,6 +28,8 @@ #define IDSETT_SERVICE_CONNECT_AUTO 24 #define IDSETT_SERVICE_MINIMIZE_AUTO 25 #define IDSETT_BLOCKINTERNET_DISCONN 26 +#define IDSETT_BLOCKINTERNET_ALLOWLOCAL 27 +#define ID_BTN_KILLSWITCH 28 #define IDC_PAINTBOX 30 #define IDC_GRAPHBOX 31 #define IDC_ADVANCEDBOX 32 @@ -41,13 +43,12 @@ #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 40026 +#define _APS_NEXT_COMMAND_VALUE 40030 #define _APS_NEXT_CONTROL_VALUE 1016 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/service_win32.cpp b/service_win32.cpp index f60f23b..b0a9600 100644 --- a/service_win32.cpp +++ b/service_win32.cpp @@ -589,13 +589,11 @@ void TunsafeServiceBackend::SendStateUpdate(TunsafeServiceServer *filter) { return; uint8 *temp = new uint8[current_filename_.size() + 1 + sizeof(ServiceState)]; - bool is_activated; memset(temp, 0, sizeof(ServiceState)); ServiceState *ss = (ServiceState *)temp; ss->is_started = backend_->is_started(); - ss->internet_block_state = backend_->GetInternetBlockState(&is_activated); - ss->internet_block_state_active = is_activated; + ss->internet_block_state = backend_->GetInternetBlockState(); ss->ipv4_ip = backend_->GetIP(); memcpy(ss->public_key, backend_->public_key(), 32); memcpy(temp + sizeof(ServiceState), current_filename_.c_str(), current_filename_.size() + 1); @@ -763,10 +761,9 @@ bool TunsafeServiceServer::HandleMessage(int type, uint8 *data, size_t size) { break; case TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE: - if (size < 1) + if (size < 2) return false; - service_backend_->backend_->SetInternetBlockState((InternetBlockState)data[0]); - service_backend_->OnStateChanged(); + service_backend_->backend_->SetInternetBlockState((InternetBlockState)Read16(data)); break; case TS_SERVICE_REQ_RESETSTATS: @@ -934,15 +931,13 @@ void TunsafeServiceClient::ResetStats() { connection_->WritePacket(TS_SERVICE_REQ_RESETSTATS, NULL, 0); } -InternetBlockState TunsafeServiceClient::GetInternetBlockState(bool *is_activated) { - if (is_activated) - *is_activated = service_state_.internet_block_state_active; +InternetBlockState TunsafeServiceClient::GetInternetBlockState() { return (InternetBlockState)service_state_.internet_block_state; } void TunsafeServiceClient::SetInternetBlockState(InternetBlockState s) { - uint8 v = (uint8)s; - connection_->WritePacket(TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE, &v, 1); + uint16 v = (uint16)s; + connection_->WritePacket(TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE, (uint8*)&v, sizeof(v)); } void TunsafeServiceClient::SetServiceStartupFlags(uint32 flags) { diff --git a/service_win32.h b/service_win32.h index 6af6e2d..d105004 100644 --- a/service_win32.h +++ b/service_win32.h @@ -162,9 +162,9 @@ private: struct ServiceState { uint8 is_started : 1; - uint8 internet_block_state_active : 1; - uint8 internet_block_state; - uint8 reserved[26 + 64]; + uint8 reserved1; + uint16 internet_block_state; + uint8 reserved[24 + 64]; uint32 ipv4_ip; uint8 public_key[32]; }; @@ -184,7 +184,7 @@ public: virtual void Stop(); virtual void RequestStats(bool enable); virtual void ResetStats(); - virtual InternetBlockState GetInternetBlockState(bool *is_activated); + virtual InternetBlockState GetInternetBlockState(); virtual void SetInternetBlockState(InternetBlockState s); virtual std::string GetConfigFileName(); virtual void SetServiceStartupFlags(uint32 flags); diff --git a/service_win32_constants.h b/service_win32_constants.h index f1c5bd1..903ad34 100644 --- a/service_win32_constants.h +++ b/service_win32_constants.h @@ -1,7 +1,7 @@ #pragma once #define TUNSAFE_PIPE_NAME "\\\\.\\pipe\\TunSafe\\ServiceControl" -#define TUNSAFE_SERVICE_PROTOCOL_VERSION 20180916001 +#define TUNSAFE_SERVICE_PROTOCOL_VERSION 20181021001 enum { TS_SERVICE_REQ_LOGIN = 0, diff --git a/tunsafe_win32.cpp b/tunsafe_win32.cpp index bddd403..05055dc 100644 --- a/tunsafe_win32.cpp +++ b/tunsafe_win32.cpp @@ -220,7 +220,11 @@ public: } } + uint32 state = g_backend->GetInternetBlockState(); bool running = g_backend->is_started(); + + ShowWindow(GetDlgItem(g_ui_window, ID_BTN_KILLSWITCH), (!running || (state & kBlockInternet_Both) == 0) && (state & kBlockInternet_Active) ? SW_SHOW : SW_HIDE); + SetDlgItemText(g_ui_window, ID_START, running ? "Re&connect" : "&Connect"); InvalidatePaintbox(); EnableWindow(GetDlgItem(g_ui_window, ID_STOP), running); @@ -813,6 +817,7 @@ enum { static const WindowSizingItem kWindowSizing[] = { {ID_START,WSI_LEFT | WSI_RIGHT}, + {ID_BTN_KILLSWITCH, WSI_LEFT | WSI_RIGHT}, {ID_STOP,WSI_LEFT | WSI_RIGHT}, {ID_EDITCONF,WSI_LEFT | WSI_RIGHT}, {IDC_PAINTBOX,WSI_RIGHT}, @@ -909,22 +914,33 @@ static void HandleClickedItem(HWND hWnd, int wParam) { case IDSETT_BLOCKINTERNET_FIREWALL: case IDSETT_BLOCKINTERNET_BOTH: { - uint32 old_state = g_backend->GetInternetBlockState(NULL); + uint32 old_state = g_backend->GetInternetBlockState(); uint32 new_state = wParam - IDSETT_BLOCKINTERNET_OFF; - if ((old_state & kBlockInternet_Both) == kBlockInternet_Off && new_state != kBlockInternet_Off) { + if ((old_state & kBlockInternet_TypeMask) == 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((InternetBlockState)(new_state | (old_state & kBlockInternet_BlockOnDisconnect))); + g_backend->SetInternetBlockState((InternetBlockState)(new_state | (old_state & ~kBlockInternet_TypeMask))); 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)); + g_backend->SetInternetBlockState((InternetBlockState)(g_backend->GetInternetBlockState() ^ kBlockInternet_BlockOnDisconnect)); + return; + } + + case IDSETT_BLOCKINTERNET_ALLOWLOCAL: { + g_backend->SetInternetBlockState((InternetBlockState)(g_backend->GetInternetBlockState() ^ kBlockInternet_AllowLocalNetworks)); + if (g_backend->is_started()) + StartTunsafeBackend(UIW_START); + return; + } + + case ID_BTN_KILLSWITCH: { + g_backend->SetInternetBlockState((InternetBlockState)(g_backend->GetInternetBlockState() & ~kBlockInternet_Active)); return; } @@ -1030,11 +1046,11 @@ static INT_PTR WINAPI DlgProc(HWND hWnd, UINT message, WPARAM wParam, CheckMenuItem(menu, IDSETT_SERVICE_MINIMIZE_AUTO, MF_CHECKED * !!(g_startup_flags & kStartupFlag_MinimizeToTrayWhenWindowsStarts)); CheckMenuItem(menu, IDSETT_PREPOST, g_allow_pre_post ? MF_CHECKED : 0); - bool is_activated = false; - int value = g_backend->GetInternetBlockState(&is_activated); + int value = g_backend->GetInternetBlockState(); 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); + CheckMenuItem(menu, IDSETT_BLOCKINTERNET_ALLOWLOCAL, (value & kBlockInternet_AllowLocalNetworks) ? MF_CHECKED : 0); break; } @@ -1691,6 +1707,8 @@ static bool CreateMainWindow() { hwndGraphBox = GetDlgItem(g_ui_window, IDC_GRAPHBOX); hwndAdvancedBox = GetDlgItem(g_ui_window, IDC_ADVANCEDBOX); + SetWindowLong(hwndPaintBox, GWL_STYLE, GetWindowLong(hwndPaintBox, GWL_STYLE) | WS_CLIPSIBLINGS); + SetWindowLong(hwndEdit, GWL_EXSTYLE, GetWindowLong(hwndEdit, GWL_EXSTYLE) &~ WS_EX_CLIENTEDGE); // Create the status bar. diff --git a/wireguard.h b/wireguard.h index 10ec2db..12f5dac 100644 --- a/wireguard.h +++ b/wireguard.h @@ -56,13 +56,14 @@ enum InternetBlockState { kBlockInternet_Route = 1, kBlockInternet_Firewall = 2, kBlockInternet_Both = 3, + kBlockInternet_TypeMask = 0xf, kBlockInternet_BlockOnDisconnect = 16, - - // An unspecified value that uses either route or firewall - kBlockInternet_DefaultOn = 254, + kBlockInternet_AllowLocalNetworks = 32, kBlockInternet_Default = 255, + + kBlockInternet_Active = 256, }; class WireguardProcessor { diff --git a/wireguard_config.cpp b/wireguard_config.cpp index 9004fad..b1638f0 100644 --- a/wireguard_config.cpp +++ b/wireguard_config.cpp @@ -140,23 +140,28 @@ bool WgFileParser::ParseFlag(const char *group, const char *key, char *value) { wg_->SetDnsBlocking(v); } else if (strcmp(key, "BlockInternet") == 0) { uint8 v = kBlockInternet_Default; - SplitString(value, ',', &ss); for (size_t i = 0; i < ss.size(); i++) { - if (strcmp(ss[i], "route") == 0) { + const char *s = ss[i]; + if (strcmp(s, "route") == 0) { if (v & 128) v = 0; v |= kBlockInternet_Route; - } else if (strcmp(ss[i], "firewall") == 0) { + } else if (strcmp(s, "firewall") == 0 || strcmp(s, "on") == 0) { if (v & 128) v = 0; v |= kBlockInternet_Firewall; - } else if (strcmp(ss[i], "off") == 0) + } else if (strcmp(s, "off") == 0) { v = 0; - else if (strcmp(ss[i], "on") == 0) - v = kBlockInternet_DefaultOn; - else if (strcmp(ss[i], "default") == 0) + } else if (strcmp(s, "default") == 0) { v = kBlockInternet_Default; - else + } else if (strcmp(s, "persist") == 0) { + if (v & 128) v = 0; + v |= kBlockInternet_BlockOnDisconnect; + } else if (strcmp(s, "allow_local") == 0) { + if (v & 128) v = 0; + v |= kBlockInternet_AllowLocalNetworks; + } else { RERROR("Unknown mode in BlockInternet: %s", ss[i]); + } } wg_->SetInternetBlocking((InternetBlockState)v);