From 07eee8af255ef8558029a36d9e078890868f8226 Mon Sep 17 00:00:00 2001 From: bol-van Date: Sat, 20 Sep 2025 13:58:01 +0300 Subject: [PATCH] winws: --wf-raw-part --- docs/changes.txt | 4 + init.d/windivert.filter.examples/README.txt | 6 +- .../windivert.discord_media+stun.txt | 29 ----- .../windivert.stun.txt | 8 -- .../windivert.wireguard.txt | 8 -- ...a.txt => windivert_part.discord_media.txt} | 7 +- .../windivert_part.stun.txt | 3 + .../windivert_part.wireguard.txt | 3 + nfq/nfqws.c | 118 +++++++++++++----- nfq/params.c | 1 + nfq/params.h | 1 + 11 files changed, 105 insertions(+), 83 deletions(-) delete mode 100644 init.d/windivert.filter.examples/windivert.discord_media+stun.txt delete mode 100644 init.d/windivert.filter.examples/windivert.stun.txt delete mode 100644 init.d/windivert.filter.examples/windivert.wireguard.txt rename init.d/windivert.filter.examples/{windivert.discord_media.txt => windivert_part.discord_media.txt} (56%) create mode 100644 init.d/windivert.filter.examples/windivert_part.stun.txt create mode 100644 init.d/windivert.filter.examples/windivert_part.wireguard.txt diff --git a/docs/changes.txt b/docs/changes.txt index 475ee9c7..d03d8d85 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -541,3 +541,7 @@ nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate init.d: custom scripts 50-discord-media, 50-stun4all init.d: windivert filters for discord media, stun, wireguard readme: hardware problems description + +v71.5 + +winws: --wf-raw-part diff --git a/init.d/windivert.filter.examples/README.txt b/init.d/windivert.filter.examples/README.txt index 5e1d7b3f..decde507 100644 --- a/init.d/windivert.filter.examples/README.txt +++ b/init.d/windivert.filter.examples/README.txt @@ -1,14 +1,14 @@ Цель этих фильтров - отсекать полезную нагрузку в режиме ядра, не насилуя процессор перенаправлением целого потока на winws. -Задействуются через `winws --wf-raw=@filename`. +Задействуются через `winws --wf-raw-part=@filename`. Может быть несколько частичных фильтров. Они могут сочетаться с --wf-tcp и --wf-udp. Однако, язык фильтров windivert не содержит операций с битовыми полями, сдвигов и побитовой логики. Поэтому фильтры получились более слабыми, способными передавать неправильную нагрузку. Дофильтрация производится силами winws. Описание языка фильтров : https://reqrypt.org/windivert-doc.html#filter_language -Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw=@windivert.discord_media+stun.txt --filter-l7=stun,discord --dpi-desync=fake` +Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw-part=@windivert_part.discord_media.txt --wf-raw-part=@windivert_part.stun.txt --filter-l7=stun,discord --dpi-desync=fake` -These filters are invoked using `winws --wf-raw=@filename`. +These filters are invoked using `winws --wf-raw-part=@filename`. Multiple filter parts are supported. They can be combined with --wf-tcp and --wf-udp. Filters are kernel mode and save great amount of CPU. However windivert cannot filter by bit fields, lacks shift and bitwise logic operations. Filters are relaxed and can pass wrong payloads. Finer filtering is done by winws. diff --git a/init.d/windivert.filter.examples/windivert.discord_media+stun.txt b/init.d/windivert.filter.examples/windivert.discord_media+stun.txt deleted file mode 100644 index da8658b8..00000000 --- a/init.d/windivert.filter.examples/windivert.discord_media+stun.txt +++ /dev/null @@ -1,29 +0,0 @@ -!impostor and !loopback and - (outbound and - ((ip and - udp.DstPort>=50000 and udp.DstPort<=50099 and - udp.PayloadLength=74 and - udp.Payload32[0]=0x00010046 and - udp.Payload32[2]=0 and - udp.Payload32[3]=0 and - udp.Payload32[4]=0 and - udp.Payload32[5]=0 and - udp.Payload32[6]=0 and - udp.Payload32[7]=0 and - udp.Payload32[8]=0 and - udp.Payload32[9]=0 and - udp.Payload32[10]=0 and - udp.Payload32[11]=0 and - udp.Payload32[12]=0 and - udp.Payload32[13]=0 and - udp.Payload32[14]=0 and - udp.Payload32[15]=0 and - udp.Payload32[16]=0 and - udp.Payload32[17]=0) - or - (udp.PayloadLength>=20 and - udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40)) and - ( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or - ((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0)) - ) - ) diff --git a/init.d/windivert.filter.examples/windivert.stun.txt b/init.d/windivert.filter.examples/windivert.stun.txt deleted file mode 100644 index 2dd4aa1a..00000000 --- a/init.d/windivert.filter.examples/windivert.stun.txt +++ /dev/null @@ -1,8 +0,0 @@ -!impostor and !loopback and - (outbound and - udp.PayloadLength>=20 and - udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40 and - ( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or - ((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0)) - ) - ) diff --git a/init.d/windivert.filter.examples/windivert.wireguard.txt b/init.d/windivert.filter.examples/windivert.wireguard.txt deleted file mode 100644 index 839b3ff9..00000000 --- a/init.d/windivert.filter.examples/windivert.wireguard.txt +++ /dev/null @@ -1,8 +0,0 @@ -!impostor and !loopback and - (outbound and - udp.PayloadLength=148 and - udp.Payload[0]=0x01 and - ( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or - ((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0)) - ) - ) diff --git a/init.d/windivert.filter.examples/windivert.discord_media.txt b/init.d/windivert.filter.examples/windivert_part.discord_media.txt similarity index 56% rename from init.d/windivert.filter.examples/windivert.discord_media.txt rename to init.d/windivert.filter.examples/windivert_part.discord_media.txt index a79dba7f..26c2014b 100644 --- a/init.d/windivert.filter.examples/windivert.discord_media.txt +++ b/init.d/windivert.filter.examples/windivert_part.discord_media.txt @@ -1,5 +1,4 @@ -!impostor and !loopback and - (outbound and + outbound and ip and udp.DstPort>=50000 and udp.DstPort<=50099 and udp.PayloadLength=74 and udp.Payload32[0]=0x00010046 and @@ -18,6 +17,4 @@ udp.Payload32[14]=0 and udp.Payload32[15]=0 and udp.Payload32[16]=0 and - udp.Payload32[17]=0 and - (ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255) - ) + udp.Payload32[17]=0 \ No newline at end of file diff --git a/init.d/windivert.filter.examples/windivert_part.stun.txt b/init.d/windivert.filter.examples/windivert_part.stun.txt new file mode 100644 index 00000000..a7616902 --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.stun.txt @@ -0,0 +1,3 @@ + outbound and + udp.PayloadLength>=20 and + udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40 \ No newline at end of file diff --git a/init.d/windivert.filter.examples/windivert_part.wireguard.txt b/init.d/windivert.filter.examples/windivert_part.wireguard.txt new file mode 100644 index 00000000..9b07c08f --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.wireguard.txt @@ -0,0 +1,3 @@ + outbound and + udp.PayloadLength=148 and + udp.Payload[0]=0x01 \ No newline at end of file diff --git a/nfq/nfqws.c b/nfq/nfqws.c index ce4e1f91..ab509dcf 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1447,37 +1447,63 @@ static bool wf_make_filter( unsigned int IfIdx,unsigned int SubIfIdx, bool ipv4, bool ipv6, const char *pf_tcp_src, const char *pf_tcp_dst, - const char *pf_udp_src, const char *pf_udp_dst) + const char *pf_udp_src, const char *pf_udp_dst, + const struct str_list_head *wf_raw_part, + bool bFilterOutLAN) { char pf_dst_buf[8192],iface[64]; + struct str_list *wfpart; + int n; const char *pf_dst; const char *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(¶ms.desync_profiles) ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : ""; const char *f_tcp_not_empty = (*pf_tcp_src && !dp_list_need_all_out(¶ms.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : ""; snprintf(iface,sizeof(iface)," ifIdx=%u and subIfIdx=%u and",IfIdx,SubIfIdx); - if (!*pf_tcp_src && !*pf_udp_src) return false; - if (*pf_tcp_src && *pf_udp_src) + snprintf(wf,len,"%s and%s%s\n(", + DIVERT_PROLOG, + IfIdx ? iface : "", + ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and" + ); + + n=0; + if (!LIST_EMPTY(wf_raw_part)) { - snprintf(pf_dst_buf,sizeof(pf_dst_buf),"(%s or %s)",pf_tcp_dst,pf_udp_dst); - pf_dst = pf_dst_buf; + LIST_FOREACH(wfpart, wf_raw_part, next) + { + snprintf(wf+strlen(wf),len-strlen(wf),"%s(\n%s\n )", n ? "\n or\n " : "\n " ,wfpart->str); + n++; + } } - else - pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst; - snprintf(wf,len, - DIVERT_PROLOG " and%s%s\n ((outbound and %s%s%s)\n or\n (inbound and tcp%s%s%s%s%s%s%s))", - IfIdx ? iface : "", - ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and", - f_tcp_not_empty, - pf_dst, - ipv4 ? ipv6 ? " and " DIVERT_NO_LOCALNETS_DST : " and " DIVERT_NO_LOCALNETSv4_DST : " and " DIVERT_NO_LOCALNETSv6_DST, - *pf_tcp_src ? "" : " and false", - *f_tcpin ? " and " : "", - *f_tcpin ? f_tcpin : "", - *pf_tcp_src ? " and " : "", - *pf_tcp_src ? pf_tcp_src : "", - *pf_tcp_src ? " and " : "", - *pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : "" - ); + + if (*pf_tcp_src || *pf_udp_src) + { + if (*pf_tcp_src && *pf_udp_src) + { + snprintf(pf_dst_buf,sizeof(pf_dst_buf),"(%s or %s)",pf_tcp_dst,pf_udp_dst); + pf_dst = pf_dst_buf; + } + else + pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst; + + snprintf(wf+strlen(wf),len-strlen(wf), n++ ? "\n or\n " : "\n "); + + snprintf(wf+strlen(wf),len-strlen(wf), + "(\n (outbound and %s%s)\n or\n (inbound and tcp%s%s%s%s%s)\n )", + f_tcp_not_empty, + pf_dst, + *pf_tcp_src ? "" : " and false", + *f_tcpin ? " and " : "", + *f_tcpin ? f_tcpin : "", + *pf_tcp_src ? " and " : "", + *pf_tcp_src ? pf_tcp_src : ""); + + } + strncat(wf,"\n)",len-strlen(wf)-1); + + if (bFilterOutLAN) + snprintf(wf+strlen(wf),len-strlen(wf),"\nand\n(\n outbound and %s\n or\n inbound and %s\n)\n", + ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_DST : DIVERT_NO_LOCALNETSv4_DST : DIVERT_NO_LOCALNETSv6_DST, + ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC); return true; } @@ -1531,7 +1557,9 @@ static void exithelp(void) " --wf-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --wf-tcp=[~]port1[-port2]\t\t\t; TCP port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-udp=[~]port1[-port2]\t\t\t; UDP port filter. ~ means negation. multiple comma separated values allowed.\n" - " --wf-raw=|@\t\t\t; raw windivert filter string or filename\n" + " --wf-raw-part=|@\t\t; partial raw windivert filter string or filename\n" + " --wf-filter-lan=0|1\t\t\t\t; add excluding filter for non-global IP (default : 1)\n" + " --wf-raw=|@\t\t\t; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part\n" " --wf-save=\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" @@ -1701,7 +1729,7 @@ void check_dp(const struct desync_profile *dp) DLOG_CONDUP("WARNING !!! fakes or dups will be sent on every processed packet\n"); DLOG_CONDUP("WARNING !!! make sure it's really what you want\n"); #ifdef __CYGWIN__ - DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw)\n"); + DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw, --wf-raw-part)\n"); #endif #endif } @@ -1841,6 +1869,8 @@ enum opt_indices { IDX_WF_TCP, IDX_WF_UDP, IDX_WF_RAW, + IDX_WF_RAW_PART, + IDX_WF_FILTER_LAN, IDX_WF_SAVE, IDX_SSID_FILTER, IDX_NLM_FILTER, @@ -1967,6 +1997,8 @@ static const struct option long_options[] = { [IDX_WF_TCP] = {"wf-tcp", required_argument, 0, 0}, [IDX_WF_UDP] = {"wf-udp", required_argument, 0, 0}, [IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0}, + [IDX_WF_RAW_PART] = {"wf-raw-part", required_argument, 0, 0}, + [IDX_WF_FILTER_LAN] = {"wf-filter-lan", required_argument, 0, 0}, [IDX_WF_SAVE] = {"wf-save", required_argument, 0, 0}, [IDX_SSID_FILTER] = {"ssid-filter", required_argument, 0, 0}, [IDX_NLM_FILTER] = {"nlm-filter", required_argument, 0, 0}, @@ -1994,9 +2026,9 @@ int main(int argc, char **argv) struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL; #ifdef __CYGWIN__ char windivert_filter[16384], wf_pf_tcp_src[4096], wf_pf_tcp_dst[4096], wf_pf_udp_src[4096], wf_pf_udp_dst[4096], wf_save_file[256]; - bool wf_ipv4=true, wf_ipv6=true; + bool wf_ipv4=true, wf_ipv6=true, wf_filter_lan=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,hash_nlm_filter=0; + unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_wf_raw_part=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 @@ -2037,6 +2069,7 @@ int main(int argc, char **argv) #ifdef __CYGWIN__ LIST_INIT(¶ms.ssid_filter); LIST_INIT(¶ms.nlm_filter); + LIST_INIT(¶ms.wf_raw_part); #else if (can_drop_root()) { @@ -2953,6 +2986,31 @@ int main(int argc, char **argv) windivert_filter[sizeof(windivert_filter) - 1] = '\0'; } break; + case IDX_WF_RAW_PART: + hash_wf_raw_part^=hash_jen(optarg,strlen(optarg)); + { + char wfpart[sizeof(windivert_filter)]; + if (optarg[0]=='@') + { + size_t sz = sizeof(wfpart)-1; + load_file_or_exit(optarg+1,wfpart,&sz); + wfpart[sz] = 0; + } + else + { + strncpy(wfpart, optarg, sizeof(wfpart)); + wfpart[sizeof(wfpart) - 1] = '\0'; + } + if (!strlist_add(¶ms.wf_raw_part,wfpart)) + { + DLOG_ERR("out of memory\n"); + exit_clean(1); + } + } + break; + case IDX_WF_FILTER_LAN: + wf_filter_lan=!!atoi(optarg); + break; case IDX_WF_SAVE: strncpy(wf_save_file, optarg, sizeof(wf_save_file)); wf_save_file[sizeof(wf_save_file) - 1] = '\0'; @@ -3093,12 +3151,12 @@ int main(int argc, char **argv) #ifdef __CYGWIN__ if (!*windivert_filter) { - if (!*wf_pf_tcp_src && !*wf_pf_udp_src) + if (!*wf_pf_tcp_src && !*wf_pf_udp_src && LIST_EMPTY(¶ms.wf_raw_part)) { - DLOG_ERR("windivert filter : must specify port filter\n"); + DLOG_ERR("windivert filter : must specify port or/and partial raw filter\n"); exit_clean(1); } - if (!wf_make_filter(windivert_filter, sizeof(windivert_filter), IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, wf_pf_tcp_src, wf_pf_tcp_dst, wf_pf_udp_src, wf_pf_udp_dst)) + if (!wf_make_filter(windivert_filter, sizeof(windivert_filter), IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, wf_pf_tcp_src, wf_pf_tcp_dst, wf_pf_udp_src, wf_pf_udp_dst, ¶ms.wf_raw_part, wf_filter_lan)) { DLOG_ERR("windivert filter : could not make filter\n"); exit_clean(1); @@ -3121,7 +3179,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_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_ssid_filter,hash_nlm_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_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_wf_raw_part,hash_ssid_filter,hash_nlm_filter,IfIdx,SubIfIdx,wf_ipv4,wf_ipv6); hMutexArg = CreateMutexA(NULL,TRUE,mutex_name); if (hMutexArg && GetLastError()==ERROR_ALREADY_EXISTS) diff --git a/nfq/params.c b/nfq/params.c index df9c1337..97d2070e 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -371,6 +371,7 @@ void cleanup_params(struct params_s *params) #ifdef __CYGWIN__ strlist_destroy(¶ms->ssid_filter); strlist_destroy(¶ms->nlm_filter); + strlist_destroy(¶ms->wf_raw_part); #else free(params->user); params->user=NULL; #endif diff --git a/nfq/params.h b/nfq/params.h index 40c4ff33..34780459 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -200,6 +200,7 @@ struct params_s #ifdef __CYGWIN__ struct str_list_head ssid_filter,nlm_filter; + struct str_list_head wf_raw_part; #else bool droproot; char *user;