Change Kill Switch behavior

This commit is contained in:
Ludvig Strigeus 2018-09-11 21:10:10 +02:00
parent e499a3d4f7
commit 437c90b6bf
8 changed files with 102 additions and 103 deletions

View file

@ -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

View file

@ -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:

View file

@ -20,6 +20,7 @@
#include "util.h"
#include <algorithm>
#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) {

View file

@ -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;
}
}
}

View file

@ -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();
bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &luid_to_allow, bool also_ipv6);
void RemoveKillSwitchFirewall();
bool GetKillSwitchFirewallActive();

View file

@ -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

View file

@ -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;
}

View file

@ -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,