Improve killswitch behavior on Win32. Now there exists a button for it.

This commit is contained in:
Ludvig Strigeus 2018-10-21 21:53:02 +02:00
parent 6dd3dcd8d5
commit 358c79a918
13 changed files with 190 additions and 125 deletions

View file

@ -60,10 +60,11 @@ BEGIN
PUSHBUTTON "&Connect",ID_START,247,3,50,14 PUSHBUTTON "&Connect",ID_START,247,3,50,14
PUSHBUTTON "&Disconnect",ID_STOP,247,19,50,14 PUSHBUTTON "&Disconnect",ID_STOP,247,19,50,14
PUSHBUTTON "&Edit Config",ID_EDITCONF,247,35,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_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_ADVANCEDBOX,"AdvancedBox",0x0,105,181,35,15
CONTROL "",IDC_GRAPHBOX,"GraphBox",0x0,239,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 CONTROL "",IDC_TAB,"SysTabControl32",WS_TABSTOP,4,49,293,122
END END
@ -166,6 +167,7 @@ BEGIN
MENUITEM "Yes, &Both Methods", IDSETT_BLOCKINTERNET_BOTH MENUITEM "Yes, &Both Methods", IDSETT_BLOCKINTERNET_BOTH
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "Block While &Disconnected", IDSETT_BLOCKINTERNET_DISCONN MENUITEM "Block While &Disconnected", IDSETT_BLOCKINTERNET_DISCONN
MENUITEM "Allow Traffic to &Local Networks", IDSETT_BLOCKINTERNET_ALLOWLOCAL
END END
POPUP "&Service Mode" POPUP "&Service Mode"
BEGIN BEGIN

View file

@ -36,12 +36,11 @@ enum {
static uint8 internet_route_blocking_state; static uint8 internet_route_blocking_state;
static SLIST_HEADER freelist_head; static SLIST_HEADER freelist_head;
static HKEY g_hklm_reg_key; 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; bool g_allow_pre_post;
static InternetBlockState GetInternetBlockState(bool *is_activated); static void DeactivateKillSwitch(uint32 want);
static void DeactivateKillSwitch(InternetBlockState want);
Packet *AllocPacket() { Packet *AllocPacket() {
Packet *packet = (Packet*)InterlockedPopEntrySList(&freelist_head); Packet *packet = (Packet*)InterlockedPopEntrySList(&freelist_head);
@ -1280,14 +1279,8 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T
dns_blocker_->RestoreDns(); dns_blocker_->RestoreDns();
} }
// Cache the state of internet blocking g_killswitch_currconn = config.internet_blocking;
GetInternetBlockState(NULL); uint8 ibs = (g_killswitch_currconn == kBlockInternet_Default) ? g_killswitch_want : g_killswitch_currconn;
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;
}
bool block_all_traffic_route = (ibs & kBlockInternet_Route) != 0; bool block_all_traffic_route = (ibs & kBlockInternet_Route) != 0;
@ -1318,24 +1311,36 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T
if (ConvertInterfaceIndexToLuid(1, &localhost_luid) || localhost_luid.Info.IfType != 24) { if (ConvertInterfaceIndexToLuid(1, &localhost_luid) || localhost_luid.Info.IfType != 24) {
RERROR("Unable to get localhost luid - while adding route based blocking."); RERROR("Unable to get localhost luid - while adding route based blocking.");
} else { } 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; 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) { if (ibs & kBlockInternet_Firewall) {
RINFO("Blocking all regular Internet traffic using firewall rules"); 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? // Configure default route?
if (config.use_ipv4_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_) { TunsafeBackendWin32::TunsafeBackendWin32(Delegate *delegate) : delegate_(delegate), dns_resolver_(&dns_blocker_) {
memset(&stats_, 0, sizeof(stats_)); memset(&stats_, 0, sizeof(stats_));
wg_processor_ = NULL; wg_processor_ = NULL;
@ -2029,6 +2045,8 @@ TunsafeBackendWin32::TunsafeBackendWin32(Delegate *delegate) : delegate_(delegat
if (g_hklm_reg_key == NULL) { if (g_hklm_reg_key == NULL) {
RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\TunSafe", NULL, NULL, 0, KEY_ALL_ACCESS, NULL, &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_want = RegReadInt(g_hklm_reg_key, "KillSwitch", 0);
g_killswitch_curr = GetKillSwitchRouteActive() * kBlockInternet_Route +
GetKillSwitchFirewallActive() * kBlockInternet_Firewall;
} }
delegate_->OnStateChanged(); delegate_->OnStateChanged();
} }
@ -2089,6 +2107,7 @@ void TunsafeBackendWin32::Stop() {
void TunsafeBackendWin32::Start(const char *config_file) { void TunsafeBackendWin32::Start(const char *config_file) {
StopInner(true); StopInner(true);
dns_resolver_.ResetCancel(); dns_resolver_.ResetCancel();
g_killswitch_currconn = kBlockInternet_Default;
is_started_ = true; is_started_ = true;
memset(public_key_, 0, sizeof(public_key_)); memset(public_key_, 0, sizeof(public_key_));
SetStatus(kStatusInitializing); SetStatus(kStatusInitializing);
@ -2118,7 +2137,8 @@ void TunsafeBackendWin32::StopInner(bool is_restart) {
status_ = kStatusStopped; status_ = kStatusStopped;
packet_processor_.Reset(); 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); DeactivateKillSwitch(kBlockInternet_Off);
} }
} }
@ -2154,35 +2174,13 @@ LinearizedGraph *TunsafeBackendWin32::GetGraph(int type) {
return graph; return graph;
} }
static bool GetKillSwitchRouteActive() { InternetBlockState TunsafeBackendWin32::GetInternetBlockState() {
RouteInfo ri; return (InternetBlockState)(g_killswitch_want | (g_killswitch_curr ? kBlockInternet_Active : 0));
return (GetDefaultRouteAndDeleteOldRoutes(AF_INET, NULL, TRUE, NULL, &ri) && ri.found_null_routes == 2);
} }
static void RemoveKillSwitchRoute() { static void DeactivateKillSwitch(uint32 want) {
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) {
// Disable blocking without reconnecting // 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 ((maybeon & kBlockInternet_Route) > (want & kBlockInternet_Route)) {
if (g_killswitch_curr & kBlockInternet_Route) { if (g_killswitch_curr & kBlockInternet_Route) {
g_killswitch_curr &= ~kBlockInternet_Route; g_killswitch_curr &= ~kBlockInternet_Route;
@ -2200,14 +2198,16 @@ static void DeactivateKillSwitch(InternetBlockState want) {
} }
void TunsafeBackendWin32::SetInternetBlockState(InternetBlockState want) { void TunsafeBackendWin32::SetInternetBlockState(InternetBlockState want) {
GetInternetBlockState(NULL); // ensure cache is read if (worker_thread_ == NULL && !(want & kBlockInternet_BlockOnDisconnect) || !(want & kBlockInternet_Active))
if (worker_thread_ == NULL && !(want & kBlockInternet_BlockOnDisconnect))
DeactivateKillSwitch(kBlockInternet_Off); DeactivateKillSwitch(kBlockInternet_Off);
else else
DeactivateKillSwitch(want); 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) { void TunsafeBackendWin32::SetServiceStartupFlags(uint32 flags) {

View file

@ -218,7 +218,7 @@ public:
virtual void Stop() override; virtual void Stop() override;
virtual void RequestStats(bool enable) override; virtual void RequestStats(bool enable) override;
virtual void ResetStats() override; virtual void ResetStats() override;
virtual InternetBlockState GetInternetBlockState(bool *is_activated) override; virtual InternetBlockState GetInternetBlockState() override;
virtual void SetInternetBlockState(InternetBlockState s) override; virtual void SetInternetBlockState(InternetBlockState s) override;
virtual void SetServiceStartupFlags(uint32 flags) override; virtual void SetServiceStartupFlags(uint32 flags) override;
virtual LinearizedGraph *GetGraph(int type) override; virtual LinearizedGraph *GetGraph(int type) override;

View file

@ -97,8 +97,9 @@ public:
virtual void RequestStats(bool enable) = 0; virtual void RequestStats(bool enable) = 0;
virtual void ResetStats() = 0; virtual void ResetStats() = 0;
virtual InternetBlockState GetInternetBlockState(bool *is_activated) = 0; virtual InternetBlockState GetInternetBlockState() = 0;
virtual void SetInternetBlockState(InternetBlockState s) = 0; virtual void SetInternetBlockState(InternetBlockState s) = 0;
virtual void SetServiceStartupFlags(uint32 flags) = 0; virtual void SetServiceStartupFlags(uint32 flags) = 0;
virtual std::string GetConfigFileName() = 0; virtual std::string GetConfigFileName() = 0;
virtual LinearizedGraph *GetGraph(int type) = 0; virtual LinearizedGraph *GetGraph(int type) = 0;

View file

@ -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}; FWPM_FILTER_ENUM_TEMPLATE0 enum_template = {0};
HANDLE enum_handle = NULL; HANDLE enum_handle = NULL;
DWORD err; DWORD err;
@ -184,7 +184,7 @@ static bool RemovePersistentInternetBlockingInner(HANDLE handle) {
} }
for (UINT32 i = 0; i < num_returned; i++) { for (UINT32 i = 0; i < num_returned; i++) {
FWPM_FILTER0 *cur_filter = filter[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); err = FwpmFilterDeleteById0(handle, cur_filter->filterId);
if (err != 0) if (err != 0)
RERROR("FwpmFilterDeleteById0 failed: %d", err); RERROR("FwpmFilterDeleteById0 failed: %d", err);
@ -197,11 +197,13 @@ static bool RemovePersistentInternetBlockingInner(HANDLE handle) {
enum_handle = NULL; enum_handle = NULL;
} }
if (destroy_sublayer) {
err = FwpmSubLayerDeleteByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER); err = FwpmSubLayerDeleteByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER);
if (err != 0 && err != FWP_E_SUBLAYER_NOT_FOUND) { if (err != 0 && err != FWP_E_SUBLAYER_NOT_FOUND) {
RERROR("FwpmSubLayerDeleteByKey0 failed: %d", err); RERROR("FwpmSubLayerDeleteByKey0 failed: %d", err);
goto getout; goto getout;
} }
}
getout: getout:
if (enum_handle != NULL) { if (enum_handle != NULL) {
@ -210,7 +212,16 @@ getout:
return false; 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; FWPM_SUBLAYER0 *sublayer_p = NULL;
FWP_BYTE_BLOB *fwp_appid = NULL; FWP_BYTE_BLOB *fwp_appid = NULL;
FWPM_FILTER0 filter; FWPM_FILTER0 filter;
@ -219,6 +230,11 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu
HANDLE handle = NULL; HANDLE handle = NULL;
bool success = false; 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}; FWPM_SESSION0 session = {0};
err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &handle); 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) { if (FwpmSubLayerGetByKey0(handle, &TUNSAFE_GLOBAL_BLOCK_SUBLAYER, &sublayer_p) == 0) {
// The sublayer already exists // The sublayer already exists
FwpmFreeMemory0((void **)&sublayer_p); FwpmFreeMemory0((void **)&sublayer_p);
if (memcmp(&last_killswitch_settings, &new_settings, sizeof(new_settings)) != 0)
RemovePersistentInternetBlockingInner(handle, false);
} else { } else {
// Add new sublayer // Add new sublayer
FWPM_SUBLAYER0 sublayer = {0}; FWPM_SUBLAYER0 sublayer = {0};
@ -273,17 +292,38 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu
filter.weight.uint8 = 14; filter.weight.uint8 = 14;
if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2))
goto getout; goto getout;
// Permit everything that's loopback // Permit everything that's loopback
filter_condition[0].fieldKey = FWPM_CONDITION_INTERFACE_TYPE; filter_condition[0].fieldKey = FWPM_CONDITION_INTERFACE_TYPE;
filter_condition[0].conditionValue.type = FWP_UINT32; filter_condition[0].conditionValue.type = FWP_UINT32;
filter_condition[0].conditionValue.uint32 = 24; filter_condition[0].conditionValue.uint32 = 24;
filter_condition[0].matchType = FWP_MATCH_EQUAL; filter_condition[0].matchType = FWP_MATCH_EQUAL;
filter.weight.uint8 = 13; filter.weight.uint8 = 13;
if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 3))
goto getout; 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) // 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].fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
filter_condition[2].matchType = FWP_MATCH_EQUAL; filter_condition[2].matchType = FWP_MATCH_EQUAL;
filter_condition[2].conditionValue.type = FWP_UINT16; filter_condition[2].conditionValue.type = FWP_UINT16;
@ -293,29 +333,31 @@ bool AddKillSwitchFirewall(const NET_LUID *default_interface, const NET_LUID &lu
filter_condition[1].conditionValue.type = FWP_UINT16; filter_condition[1].conditionValue.type = FWP_UINT16;
filter_condition[1].conditionValue.uint16 = 67; filter_condition[1].conditionValue.uint16 = 67;
filter.numFilterConditions = 3; filter.numFilterConditions = 3;
filter_condition[0].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; filter_condition[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
filter_condition[0].conditionValue.type = FWP_UINT64; filter_condition[0].conditionValue.type = FWP_UINT8;
filter_condition[0].conditionValue.uint64 = (uint64*)&default_interface->Value; filter_condition[0].conditionValue.uint8 = 17; // UDP
filter_condition[0].matchType = FWP_MATCH_EQUAL; filter_condition[0].matchType = FWP_MATCH_EQUAL;
filter.weight.uint8 = 12; filter.weight.uint8 = 12;
if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 2)) if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 5))
goto getout; goto getout;
}
// Block the rest // Block the rest
filter.numFilterConditions = 0; filter.numFilterConditions = 0;
filter.weight.type = FWP_EMPTY; filter.weight.type = FWP_EMPTY;
filter.action.type = FWP_ACTION_BLOCK; filter.action.type = FWP_ACTION_BLOCK;
if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 3)) if (!FwpmFilterAddCheckedAleConnect(handle, &filter, also_ipv6, 6))
goto getout; goto getout;
success = true; success = true;
last_killswitch_settings = new_settings;
getout: getout:
if (handle != NULL) {
// delete the layer on failure
if (!success) if (!success)
RemovePersistentInternetBlockingInner(handle); memset(&last_killswitch_settings, 0, sizeof(last_killswitch_settings));
if (handle != NULL) {
if (!success)
RemovePersistentInternetBlockingInner(handle, true);
FwpmEngineClose0(handle); FwpmEngineClose0(handle);
handle = NULL; handle = NULL;
} }
@ -345,7 +387,7 @@ void RemoveKillSwitchFirewall() {
goto getout; goto getout;
} }
RemovePersistentInternetBlockingInner(handle); RemovePersistentInternetBlockingInner(handle, true);
getout: getout:
if (handle != NULL) { if (handle != NULL) {

View file

@ -18,6 +18,6 @@ public:
bool also_ipv6_; 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(); void RemoveKillSwitchFirewall();
bool GetKillSwitchFirewallActive(); bool GetKillSwitchFirewallActive();

View file

@ -28,6 +28,8 @@
#define IDSETT_SERVICE_CONNECT_AUTO 24 #define IDSETT_SERVICE_CONNECT_AUTO 24
#define IDSETT_SERVICE_MINIMIZE_AUTO 25 #define IDSETT_SERVICE_MINIMIZE_AUTO 25
#define IDSETT_BLOCKINTERNET_DISCONN 26 #define IDSETT_BLOCKINTERNET_DISCONN 26
#define IDSETT_BLOCKINTERNET_ALLOWLOCAL 27
#define ID_BTN_KILLSWITCH 28
#define IDC_PAINTBOX 30 #define IDC_PAINTBOX 30
#define IDC_GRAPHBOX 31 #define IDC_GRAPHBOX 31
#define IDC_ADVANCEDBOX 32 #define IDC_ADVANCEDBOX 32
@ -41,13 +43,12 @@
#define IDC_PUBLIC_KEY 109 #define IDC_PUBLIC_KEY 109
#define IDC_TAB 110 #define IDC_TAB 110
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 113 #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_CONTROL_VALUE 1016
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif

View file

@ -589,13 +589,11 @@ void TunsafeServiceBackend::SendStateUpdate(TunsafeServiceServer *filter) {
return; return;
uint8 *temp = new uint8[current_filename_.size() + 1 + sizeof(ServiceState)]; uint8 *temp = new uint8[current_filename_.size() + 1 + sizeof(ServiceState)];
bool is_activated;
memset(temp, 0, sizeof(ServiceState)); memset(temp, 0, sizeof(ServiceState));
ServiceState *ss = (ServiceState *)temp; ServiceState *ss = (ServiceState *)temp;
ss->is_started = backend_->is_started(); ss->is_started = backend_->is_started();
ss->internet_block_state = backend_->GetInternetBlockState(&is_activated); ss->internet_block_state = backend_->GetInternetBlockState();
ss->internet_block_state_active = is_activated;
ss->ipv4_ip = backend_->GetIP(); ss->ipv4_ip = backend_->GetIP();
memcpy(ss->public_key, backend_->public_key(), 32); memcpy(ss->public_key, backend_->public_key(), 32);
memcpy(temp + sizeof(ServiceState), current_filename_.c_str(), current_filename_.size() + 1); 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; break;
case TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE: case TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE:
if (size < 1) if (size < 2)
return false; return false;
service_backend_->backend_->SetInternetBlockState((InternetBlockState)data[0]); service_backend_->backend_->SetInternetBlockState((InternetBlockState)Read16(data));
service_backend_->OnStateChanged();
break; break;
case TS_SERVICE_REQ_RESETSTATS: case TS_SERVICE_REQ_RESETSTATS:
@ -934,15 +931,13 @@ void TunsafeServiceClient::ResetStats() {
connection_->WritePacket(TS_SERVICE_REQ_RESETSTATS, NULL, 0); connection_->WritePacket(TS_SERVICE_REQ_RESETSTATS, NULL, 0);
} }
InternetBlockState TunsafeServiceClient::GetInternetBlockState(bool *is_activated) { InternetBlockState TunsafeServiceClient::GetInternetBlockState() {
if (is_activated)
*is_activated = service_state_.internet_block_state_active;
return (InternetBlockState)service_state_.internet_block_state; return (InternetBlockState)service_state_.internet_block_state;
} }
void TunsafeServiceClient::SetInternetBlockState(InternetBlockState s) { void TunsafeServiceClient::SetInternetBlockState(InternetBlockState s) {
uint8 v = (uint8)s; uint16 v = (uint16)s;
connection_->WritePacket(TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE, &v, 1); connection_->WritePacket(TS_SERVICE_REQ_SET_INTERNET_BLOCKSTATE, (uint8*)&v, sizeof(v));
} }
void TunsafeServiceClient::SetServiceStartupFlags(uint32 flags) { void TunsafeServiceClient::SetServiceStartupFlags(uint32 flags) {

View file

@ -162,9 +162,9 @@ private:
struct ServiceState { struct ServiceState {
uint8 is_started : 1; uint8 is_started : 1;
uint8 internet_block_state_active : 1; uint8 reserved1;
uint8 internet_block_state; uint16 internet_block_state;
uint8 reserved[26 + 64]; uint8 reserved[24 + 64];
uint32 ipv4_ip; uint32 ipv4_ip;
uint8 public_key[32]; uint8 public_key[32];
}; };
@ -184,7 +184,7 @@ public:
virtual void Stop(); virtual void Stop();
virtual void RequestStats(bool enable); virtual void RequestStats(bool enable);
virtual void ResetStats(); virtual void ResetStats();
virtual InternetBlockState GetInternetBlockState(bool *is_activated); virtual InternetBlockState GetInternetBlockState();
virtual void SetInternetBlockState(InternetBlockState s); virtual void SetInternetBlockState(InternetBlockState s);
virtual std::string GetConfigFileName(); virtual std::string GetConfigFileName();
virtual void SetServiceStartupFlags(uint32 flags); virtual void SetServiceStartupFlags(uint32 flags);

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#define TUNSAFE_PIPE_NAME "\\\\.\\pipe\\TunSafe\\ServiceControl" #define TUNSAFE_PIPE_NAME "\\\\.\\pipe\\TunSafe\\ServiceControl"
#define TUNSAFE_SERVICE_PROTOCOL_VERSION 20180916001 #define TUNSAFE_SERVICE_PROTOCOL_VERSION 20181021001
enum { enum {
TS_SERVICE_REQ_LOGIN = 0, TS_SERVICE_REQ_LOGIN = 0,

View file

@ -220,7 +220,11 @@ public:
} }
} }
uint32 state = g_backend->GetInternetBlockState();
bool running = g_backend->is_started(); 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"); SetDlgItemText(g_ui_window, ID_START, running ? "Re&connect" : "&Connect");
InvalidatePaintbox(); InvalidatePaintbox();
EnableWindow(GetDlgItem(g_ui_window, ID_STOP), running); EnableWindow(GetDlgItem(g_ui_window, ID_STOP), running);
@ -813,6 +817,7 @@ enum {
static const WindowSizingItem kWindowSizing[] = { static const WindowSizingItem kWindowSizing[] = {
{ID_START,WSI_LEFT | WSI_RIGHT}, {ID_START,WSI_LEFT | WSI_RIGHT},
{ID_BTN_KILLSWITCH, WSI_LEFT | WSI_RIGHT},
{ID_STOP,WSI_LEFT | WSI_RIGHT}, {ID_STOP,WSI_LEFT | WSI_RIGHT},
{ID_EDITCONF,WSI_LEFT | WSI_RIGHT}, {ID_EDITCONF,WSI_LEFT | WSI_RIGHT},
{IDC_PAINTBOX,WSI_RIGHT}, {IDC_PAINTBOX,WSI_RIGHT},
@ -909,22 +914,33 @@ static void HandleClickedItem(HWND hWnd, int wParam) {
case IDSETT_BLOCKINTERNET_FIREWALL: case IDSETT_BLOCKINTERNET_FIREWALL:
case IDSETT_BLOCKINTERNET_BOTH: case IDSETT_BLOCKINTERNET_BOTH:
{ {
uint32 old_state = g_backend->GetInternetBlockState(NULL); uint32 old_state = g_backend->GetInternetBlockState();
uint32 new_state = wParam - IDSETT_BLOCKINTERNET_OFF; 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) 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; 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()) if ((~old_state & new_state) && g_backend->is_started())
StartTunsafeBackend(UIW_START); StartTunsafeBackend(UIW_START);
return; return;
} }
case IDSETT_BLOCKINTERNET_DISCONN: { case IDSETT_BLOCKINTERNET_DISCONN: {
uint32 old_state = g_backend->GetInternetBlockState(NULL); g_backend->SetInternetBlockState((InternetBlockState)(g_backend->GetInternetBlockState() ^ kBlockInternet_BlockOnDisconnect));
g_backend->SetInternetBlockState((InternetBlockState)(old_state ^ 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; 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_SERVICE_MINIMIZE_AUTO, MF_CHECKED * !!(g_startup_flags & kStartupFlag_MinimizeToTrayWhenWindowsStarts));
CheckMenuItem(menu, IDSETT_PREPOST, g_allow_pre_post ? MF_CHECKED : 0); CheckMenuItem(menu, IDSETT_PREPOST, g_allow_pre_post ? MF_CHECKED : 0);
bool is_activated = false; int value = g_backend->GetInternetBlockState();
int value = g_backend->GetInternetBlockState(&is_activated);
CheckMenuRadioItem(menu, IDSETT_BLOCKINTERNET_OFF, IDSETT_BLOCKINTERNET_BOTH, IDSETT_BLOCKINTERNET_OFF + (value & kBlockInternet_Both), 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); 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_DISCONN, (value & kBlockInternet_BlockOnDisconnect) ? MF_CHECKED : 0);
CheckMenuItem(menu, IDSETT_BLOCKINTERNET_ALLOWLOCAL, (value & kBlockInternet_AllowLocalNetworks) ? MF_CHECKED : 0);
break; break;
} }
@ -1691,6 +1707,8 @@ static bool CreateMainWindow() {
hwndGraphBox = GetDlgItem(g_ui_window, IDC_GRAPHBOX); hwndGraphBox = GetDlgItem(g_ui_window, IDC_GRAPHBOX);
hwndAdvancedBox = GetDlgItem(g_ui_window, IDC_ADVANCEDBOX); 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); SetWindowLong(hwndEdit, GWL_EXSTYLE, GetWindowLong(hwndEdit, GWL_EXSTYLE) &~ WS_EX_CLIENTEDGE);
// Create the status bar. // Create the status bar.

View file

@ -56,13 +56,14 @@ enum InternetBlockState {
kBlockInternet_Route = 1, kBlockInternet_Route = 1,
kBlockInternet_Firewall = 2, kBlockInternet_Firewall = 2,
kBlockInternet_Both = 3, kBlockInternet_Both = 3,
kBlockInternet_TypeMask = 0xf,
kBlockInternet_BlockOnDisconnect = 16, kBlockInternet_BlockOnDisconnect = 16,
kBlockInternet_AllowLocalNetworks = 32,
// An unspecified value that uses either route or firewall
kBlockInternet_DefaultOn = 254,
kBlockInternet_Default = 255, kBlockInternet_Default = 255,
kBlockInternet_Active = 256,
}; };
class WireguardProcessor { class WireguardProcessor {

View file

@ -140,24 +140,29 @@ bool WgFileParser::ParseFlag(const char *group, const char *key, char *value) {
wg_->SetDnsBlocking(v); wg_->SetDnsBlocking(v);
} else if (strcmp(key, "BlockInternet") == 0) { } else if (strcmp(key, "BlockInternet") == 0) {
uint8 v = kBlockInternet_Default; uint8 v = kBlockInternet_Default;
SplitString(value, ',', &ss); SplitString(value, ',', &ss);
for (size_t i = 0; i < ss.size(); i++) { 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; if (v & 128) v = 0;
v |= kBlockInternet_Route; 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; if (v & 128) v = 0;
v |= kBlockInternet_Firewall; v |= kBlockInternet_Firewall;
} else if (strcmp(ss[i], "off") == 0) } else if (strcmp(s, "off") == 0) {
v = 0; v = 0;
else if (strcmp(ss[i], "on") == 0) } else if (strcmp(s, "default") == 0) {
v = kBlockInternet_DefaultOn;
else if (strcmp(ss[i], "default") == 0)
v = kBlockInternet_Default; 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]); RERROR("Unknown mode in BlockInternet: %s", ss[i]);
} }
}
wg_->SetInternetBlocking((InternetBlockState)v); wg_->SetInternetBlocking((InternetBlockState)v);
} else if (strcmp(key, "HeaderObfuscation") == 0) { } else if (strcmp(key, "HeaderObfuscation") == 0) {