winws: NLM filter

This commit is contained in:
bol-van
2024-07-12 15:13:18 +03:00
parent 5a6dcb658b
commit 7e2ed880dc
10 changed files with 282 additions and 22 deletions

View File

@@ -5,7 +5,7 @@ CFLAGS_MAC = -mmacosx-version-min=10.8
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LIBS_BSD = -lz
LIBS_CYGWIN = -lz -Lwindivert -lwindivert -lwlanapi
LIBS_CYGWIN = -lz -Lwindivert -lwindivert -lwlanapi -lole32 -loleaut32 -luuid
SRC_FILES = *.c crypto/*.c
all: nfqws

View File

@@ -16,6 +16,7 @@
#ifdef __CYGWIN__
#include <wlanapi.h>
#include <netlistmgr.h>
#endif
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
@@ -963,10 +964,204 @@ void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize, uint8_t scale_fac
static HANDLE w_filter = NULL;
static OVERLAPPED ovl = { .hEvent = NULL };
static const struct str_list_head *wlan_filter_ssid = NULL;
static DWORD wlan_filter_tick=0;
static const struct str_list_head *nlm_filter_net = NULL;
static DWORD logical_net_filter_tick=0;
uint32_t w_win32_error=0;
INetworkListManager* pNetworkListManager=NULL;
bool wlan_filter_match(const struct str_list_head *ssid_list)
static void guid2str(const GUID *guid, char *str)
{
snprintf(str,37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
static bool str2guid(const char* str, GUID *guid)
{
unsigned int u[11],k;
if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", u+0, u+1, u+2, u+3, u+4, u+5, u+6, u+7, u+8, u+9, u+10))
return false;
guid->Data1 = u[0];
if ((u[1] & 0xFFFF0000) || (u[2] & 0xFFFF0000)) return false;
guid->Data2 = (USHORT)u[1];
guid->Data3 = (USHORT)u[2];
for (k = 0; k < 8; k++)
{
if (u[k+3] & 0xFFFFFF00) return false;
guid->Data4[k] = (UCHAR)u[k+3];
}
return true;
}
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter)
{
win_dark_deinit();
wlan_filter_ssid = LIST_EMPTY(ssid_filter) ? NULL : ssid_filter;
nlm_filter_net = LIST_EMPTY(nlm_filter) ? NULL : nlm_filter;
if (nlm_filter_net)
{
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
{
if (FAILED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID*)&pNetworkListManager)))
{
win_dark_deinit();
return false;
}
}
}
return true;
}
bool win_dark_deinit(void)
{
if (pNetworkListManager)
{
pNetworkListManager->lpVtbl->Release(pNetworkListManager);
pNetworkListManager = NULL;
}
if (nlm_filter_net) CoUninitialize();
wlan_filter_ssid = nlm_filter_net = NULL;
}
bool nlm_list(bool bAll)
{
bool bRet = true;
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
{
INetworkListManager* pNetworkListManager;
if (SUCCEEDED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID*)&pNetworkListManager)))
{
IEnumNetworks* pEnum;
if (SUCCEEDED(w_win32_error = pNetworkListManager->lpVtbl->GetNetworks(pNetworkListManager, NLM_ENUM_NETWORK_ALL, &pEnum)))
{
INetwork* pNet;
VARIANT_BOOL bIsConnected, bIsConnectedInet;
GUID idNet;
BSTR bstrName;
char Name[128];
int connected;
for (connected = 1; connected >= !bAll; connected--)
{
for (;;)
{
if (FAILED(w_win32_error = pEnum->lpVtbl->Next(pEnum, 1, &pNet, NULL)))
{
bRet = false;
break;
}
if (!pNet) break;
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnected(pNet, &bIsConnected)) &&
SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnectedToInternet(pNet, &bIsConnectedInet)) &&
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetName(pNet, &bstrName)))
{
if (!!bIsConnected == connected)
{
if (WideCharToMultiByte(CP_UTF8, 0, bstrName, -1, Name, sizeof(Name), NULL, NULL))
{
printf("Name : %s", Name);
if (bIsConnected) printf(" (connected)");
if (bIsConnectedInet) printf(" (inet)");
printf("\n");
guid2str(&idNet, Name);
printf("NetID : %s\n", Name);
printf("\n");
}
else
{
w_win32_error = HRESULT_FROM_WIN32(GetLastError());
bRet = false;
}
}
SysFreeString(bstrName);
}
else
bRet = false;
pNet->lpVtbl->Release(pNet);
if (!bRet) break;
}
if (!bRet) break;
pEnum->lpVtbl->Reset(pEnum);
}
pEnum->lpVtbl->Release(pEnum);
}
else
bRet = false;
pNetworkListManager->lpVtbl->Release(pNetworkListManager);
}
else
bRet = false;
}
else
bRet = false;
CoUninitialize();
return bRet;
}
static bool nlm_filter_match(const struct str_list_head *nlm_list)
{
// no filter given. always matches.
if (!nlm_list || LIST_EMPTY(nlm_list))
{
w_win32_error = 0;
return true;
}
bool bRet = true, bMatch = false;
IEnumNetworks* pEnum;
if (SUCCEEDED(w_win32_error = pNetworkListManager->lpVtbl->GetNetworks(pNetworkListManager, NLM_ENUM_NETWORK_ALL, &pEnum)))
{
INetwork* pNet;
VARIANT_BOOL bIsConnected;
GUID idNet,g;
BSTR bstrName;
char Name[128];
struct str_list *nlm;
for (;;)
{
if (FAILED(w_win32_error = pEnum->lpVtbl->Next(pEnum, 1, &pNet, NULL)))
{
bRet = false;
break;
}
if (!pNet) break;
if (SUCCEEDED(w_win32_error = pNet->lpVtbl->get_IsConnected(pNet, &bIsConnected)) &&
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetNetworkId(pNet, &idNet)) &&
SUCCEEDED(w_win32_error = pNet->lpVtbl->GetName(pNet, &bstrName)))
{
if (bIsConnected)
{
if (WideCharToMultiByte(CP_UTF8, 0, bstrName, -1, Name, sizeof(Name), NULL, NULL))
{
LIST_FOREACH(nlm, nlm_list, next)
{
bMatch = !strcmp(Name,nlm->str) || str2guid(nlm->str,&g) && !memcmp(&idNet,&g,sizeof(GUID));
if (bMatch) break;
}
}
else
{
w_win32_error = HRESULT_FROM_WIN32(GetLastError());
bRet = false;
}
}
SysFreeString(bstrName);
}
else
bRet = false;
pNet->lpVtbl->Release(pNet);
if (!bRet || bMatch) break;
}
pEnum->lpVtbl->Release(pEnum);
}
else
bRet = false;
return bRet && bMatch;
}
static bool wlan_filter_match(const struct str_list_head *ssid_list)
{
DWORD dwCurVersion;
HANDLE hClient = NULL;
@@ -1031,12 +1226,17 @@ found:
goto ex;
}
static bool wlan_filter_match_rate_limited(void)
bool logical_net_filter_match(void)
{
return wlan_filter_match(wlan_filter_ssid) && nlm_filter_match(nlm_filter_net);
}
static bool logical_net_filter_match_rate_limited(void)
{
DWORD dwTick = GetTickCount() / 1000;
if (wlan_filter_tick == dwTick) return true;
wlan_filter_tick = dwTick;
return wlan_filter_match(wlan_filter_ssid);
if (logical_net_filter_tick == dwTick) return true;
logical_net_filter_tick = dwTick;
return logical_net_filter_match();
}
static HANDLE windivert_init_filter(const char *filter, UINT64 flags)
@@ -1084,9 +1284,8 @@ void rawsend_cleanup(void)
CloseHandle(ovl.hEvent);
ovl.hEvent=NULL;
}
wlan_filter_ssid = NULL;
}
bool windivert_init(const char *filter, const struct str_list_head *ssid_filter)
bool windivert_init(const char *filter)
{
rawsend_cleanup();
w_filter = windivert_init_filter(filter, 0);
@@ -1099,7 +1298,6 @@ bool windivert_init(const char *filter, const struct str_list_head *ssid_filter)
rawsend_cleanup();
return false;
}
wlan_filter_ssid = ssid_filter;
return true;
}
return false;
@@ -1117,7 +1315,7 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
errno=EINTR;
return false;
}
if (!wlan_filter_match_rate_limited())
if (!logical_net_filter_match_rate_limited())
{
errno=ENODEV;
return false;
@@ -1142,7 +1340,7 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
errno=EINTR;
return false;
}
if (!wlan_filter_match_rate_limited())
if (!logical_net_filter_match_rate_limited())
{
errno=ENODEV;
return false;

View File

@@ -152,10 +152,13 @@ bool tcp_has_fastopen(const struct tcphdr *tcp);
#ifdef __CYGWIN__
extern uint32_t w_win32_error;
bool windivert_init(const char *filter, const struct str_list_head *ssid_filter);
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter);
bool win_dark_deinit(void);
bool logical_net_filter_match(void);
bool nlm_list(bool bAll);
bool windivert_init(const char *filter);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa);
bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa);
bool wlan_filter_match(const struct str_list_head *ssid_list);
#else
// should pre-do it if dropping privileges. otherwise its not necessary
bool rawsend_preinit(bool bind_fix4, bool bind_fix6);

View File

@@ -7,7 +7,6 @@
#include "hostlist.h"
#include "conntrack.h"
#include <unistd.h>
#include <string.h>

View File

@@ -412,9 +412,15 @@ static int win_main(const char *windivert_filter)
pre_desync();
if (!win_dark_init(&params.ssid_filter, &params.nlm_filter))
{
fprintf(stderr, "win_dark_init failed. win32 error %u (0x%08X)\n", w_win32_error, w_win32_error);
return w_win32_error;
}
for(;;)
{
if (!wlan_filter_match(&params.ssid_filter))
if (!logical_net_filter_match())
{
printf("logical network is not present. waiting it to appear.\n");
fflush(stdout);
@@ -423,17 +429,21 @@ static int win_main(const char *windivert_filter)
if (bQuit)
{
DLOG("QUIT requested\n")
win_dark_deinit();
return 0;
}
usleep(500000);
}
while (!wlan_filter_match(&params.ssid_filter));
while (!logical_net_filter_match());
printf("logical network now present\n");
fflush(stdout);
}
if (!windivert_init(windivert_filter, &params.ssid_filter))
if (!windivert_init(windivert_filter))
{
win_dark_deinit();
return w_win32_error;
}
printf("windivert initialized. capture is started.\n");
@@ -460,9 +470,11 @@ static int win_main(const char *windivert_filter)
else if (errno==EINTR)
{
DLOG("QUIT requested\n")
win_dark_deinit();
return 0;
}
fprintf(stderr, "windivert: recv failed. errno %d\n", errno);
win_dark_deinit();
return w_win32_error;
}
*ifout=0;
@@ -504,6 +516,7 @@ static int win_main(const char *windivert_filter)
fflush(stderr);
}
}
win_dark_deinit();
return 0;
}
@@ -550,6 +563,7 @@ static void cleanup_params(void)
HostFailPoolDestroy(&params.hostlist_auto_fail_counters);
#ifdef __CYGWIN__
strlist_destroy(&params.ssid_filter);
strlist_destroy(&params.nlm_filter);
#endif
}
static void exit_clean(int code)
@@ -799,6 +813,8 @@ static void exithelp(void)
" --wf-save=<filename>\t\t\t\t; save windivert filter string to a file and exit\n"
"\nLOGICAL NETWORK FILTER:\n"
" --ssid-filter=ssid1[,ssid2,ssid3,...]\t\t; enable winws only if any of specified wifi SSIDs connected\n"
" --nlm-filter=net1[,net2,net3,...]\t\t; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.\n"
" --nlm-list[=all]\t\t\t\t; list Network List Manager (NLM) networks. connected only or all.\n"
#endif
"\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
@@ -910,7 +926,7 @@ int main(int argc, char **argv)
char windivert_filter[8192], wf_pf_tcp_src[256], wf_pf_tcp_dst[256], wf_pf_udp_src[256], wf_pf_udp_dst[256], wf_save_file[256];
bool wf_ipv4=true, wf_ipv6=true;
unsigned int IfIdx=0, SubIfIdx=0;
unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0;
unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0,hash_nlm_filter=0;
*windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0;
#endif
@@ -959,6 +975,7 @@ int main(int argc, char **argv)
#ifdef __CYGWIN__
LIST_INIT(&params.ssid_filter);
LIST_INIT(&params.nlm_filter);
#else
if (can_drop_root()) // are we root ?
{
@@ -1049,6 +1066,8 @@ int main(int argc, char **argv)
{"wf-raw",required_argument,0,0}, // optidx=56
{"wf-save",required_argument,0,0}, // optidx=57
{"ssid-filter",required_argument,0,0}, // optidx=58
{"nlm-filter",required_argument,0,0}, // optidx=59
{"nlm-list",optional_argument,0,0}, // optidx=60
#endif
{NULL,0,NULL,0}
};
@@ -1582,6 +1601,31 @@ int main(int argc, char **argv)
}
}
break;
case 59: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
while (p)
{
e = strchr(p,',');
if (e) *e++=0;
if (*p && !strlist_add(&params.nlm_filter, p))
{
fprintf(stderr, "strlist_add failed\n");
exit_clean(1);
}
p = e;
}
}
break;
case 60: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all")))
{
fprintf(stderr, "could not get list of NLM networks\n");
exit_clean(1);
}
exit_clean(0);
#endif
}
@@ -1630,7 +1674,7 @@ int main(int argc, char **argv)
HANDLE hMutexArg;
{
char mutex_name[128];
snprintf(mutex_name,sizeof(mutex_name),"Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_ssid_filter,IfIdx,SubIfIdx,wf_ipv4,wf_ipv6);
snprintf(mutex_name,sizeof(mutex_name),"Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_ssid_filter,hash_nlm_filter,IfIdx,SubIfIdx,wf_ipv4,wf_ipv6);
hMutexArg = CreateMutexA(NULL,TRUE,mutex_name);
if (hMutexArg && GetLastError()==ERROR_ALREADY_EXISTS)

View File

@@ -66,7 +66,7 @@ struct params_s
int udplen_increment;
#ifdef __CYGWIN__
struct str_list_head ssid_filter;
struct str_list_head ssid_filter,nlm_filter;
#else
bool droproot;
uid_t uid;