diff --git a/binaries/win64/winws.exe b/binaries/win64/winws.exe index 93d428e..73a0a47 100644 Binary files a/binaries/win64/winws.exe and b/binaries/win64/winws.exe differ diff --git a/binaries/win64/zapret-winws/autohostlist.txt b/binaries/win64/zapret-winws/autohostlist.txt new file mode 100644 index 0000000..05dfcc5 --- /dev/null +++ b/binaries/win64/zapret-winws/autohostlist.txt @@ -0,0 +1,6 @@ +ej.ru +bbc.com +static.rutracker.cc +nnmclub.to +hdrezka.ag +rutracker.org diff --git a/binaries/win64/zapret-winws/preset_russia.cmd b/binaries/win64/zapret-winws/preset_russia.cmd index c3e5a52..9d0758d 100644 --- a/binaries/win64/zapret-winws/preset_russia.cmd +++ b/binaries/win64/zapret-winws/preset_russia.cmd @@ -1,2 +1,2 @@ start "zapret: http,https" "%~dp0winws.exe" --wf-tcp=80,443 --dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig -start "zapret: quic" "%~dp0winws.exe" --wf-udp=443 --dpi-desync=fake --dpi-desync-repeats=10 \ No newline at end of file +start "zapret: quic" "%~dp0winws.exe" --wf-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 \ No newline at end of file diff --git a/binaries/win64/zapret-winws/service_create.cmd b/binaries/win64/zapret-winws/service_create.cmd new file mode 100644 index 0000000..88b9578 --- /dev/null +++ b/binaries/win64/zapret-winws/service_create.cmd @@ -0,0 +1,12 @@ +set ARGS=--wf-l3=ipv4,ipv6 --wf-tcp=80,443 --dpi-desync=fake,split --dpi-desync-ttl=7 --dpi-desync-fooling=md5sig +call :srvinst winws1 +rem set ARGS=--wf-l3=ipv4,ipv6 --wf-udp=443 --dpi-desync=fake +rem call :srvinst winws2 +goto :eof + +:srvinst +net stop %1 +sc delete %1 +sc create %1 binPath= "\"%~dp0winws.exe\" %ARGS%" DisplayName= "zapret DPI bypass : %1" start= auto +sc description %1 "zapret DPI bypass software" +sc start %1 diff --git a/binaries/win64/zapret-winws/service_del.cmd b/binaries/win64/zapret-winws/service_del.cmd new file mode 100644 index 0000000..0475692 --- /dev/null +++ b/binaries/win64/zapret-winws/service_del.cmd @@ -0,0 +1,7 @@ +call :srvdel winws1 +rem call :srvdel winws2 +goto :eof + +:srvdel +net stop %1 +sc delete %1 diff --git a/binaries/win64/zapret-winws/service_start.cmd b/binaries/win64/zapret-winws/service_start.cmd new file mode 100644 index 0000000..ec13738 --- /dev/null +++ b/binaries/win64/zapret-winws/service_start.cmd @@ -0,0 +1,2 @@ +sc start winws1 +rem sc start winws2 diff --git a/binaries/win64/zapret-winws/service_stop.cmd b/binaries/win64/zapret-winws/service_stop.cmd new file mode 100644 index 0000000..443af87 --- /dev/null +++ b/binaries/win64/zapret-winws/service_stop.cmd @@ -0,0 +1,2 @@ +net stop winws1 +rem net stop winws2 diff --git a/binaries/win64/zapret-winws/winws.exe b/binaries/win64/zapret-winws/winws.exe index 93d428e..73a0a47 100644 Binary files a/binaries/win64/zapret-winws/winws.exe and b/binaries/win64/zapret-winws/winws.exe differ diff --git a/docs/quick_start_windows.txt b/docs/quick_start_windows.txt index ab2b815..2520146 100644 --- a/docs/quick_start_windows.txt +++ b/docs/quick_start_windows.txt @@ -89,6 +89,7 @@ badseq может работать только на https и не работа 8) Обеспечьте удобную загрузку обхода блокировок. Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя. +Последний вариант разделяется на запуск через планировщик задач и через службы windows. Если хотите ручной запуск, скопируйте preset_russia.cmd в preset_my.cmd и адаптируйте его под ваши параметра запуска. Потом можно создать ярлык на рабочем столе на preset_my.cmd. Не забудьте, что требуется запускать от имени администратора. @@ -100,6 +101,8 @@ badseq может работать только на https и не работа для поддержки нескольких задач : winws1,winws2,winws3. После создания задач запустите их. Проверьте, что обход встает после перезагрузки windows. +Аналогично настраиваются и службы windows. Смотрите service_*.cmd + 9) Если ломаются отдельные незаблокированные ресурсы, используйте хост-листы. Где они будут находиться - решайте сами. Параметры управления хост-листами точно такие же, как в *nix. diff --git a/docs/windows.txt b/docs/windows.txt index e4f1b64..988afd2 100644 --- a/docs/windows.txt +++ b/docs/windows.txt @@ -114,13 +114,16 @@ cygwin для обычной работы winws не нужен. Разве чт автозапуск winws ---------------- -Для запуска winws вместе с windows воспользуйтесь планировщиком задач windows. -Удобнее всего создавать задачи и управлять ими через консольную программу schtasks. +Для запуска winws вместе с windows есть 2 варианта. Планировщик задач или службы windows. + +Можно создавать задачи и управлять ими через консольную программу schtasks. В директории binaries/win64/winws подготовлены файлы task_*.cmd . В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной %WINWS1%. Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код для задач winws1,winws2,winws3,... +Аналогично настраивается вариант запуска через службы windows. Смотрите service_*.cmd. + Все батники требуется запускать от имени администратора. Управлять задачами можно так же из графической программы управления планировщиком taskschd.msc diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 37bb34b..bfcfdf0 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -12,6 +12,7 @@ #include "darkmagic.h" #include "helpers.h" #include "params.h" +#include "nfqws.h" uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) @@ -1016,6 +1017,11 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, DWORD rd; char c; + if (bQuit) + { + errno=EINTR; + return false; + } if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, NULL, &ovl)) { *len = recv_len; @@ -1028,7 +1034,15 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, { case ERROR_IO_PENDING: // make signals working - while(WaitForSingleObject(w_event,50)==WAIT_TIMEOUT) usleep(0); + while (WaitForSingleObject(w_event,50)==WAIT_TIMEOUT) + { + if (bQuit) + { + errno=EINTR; + return false; + } + usleep(0); + } if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE)) continue; *len = rd; @@ -1439,6 +1453,48 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl) return fake; } +void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6) +{ + uint16_t nport; + + if (ip && target4) + { + nport = target4->sin_port; + if (bOutbound) + ip->ip_dst = target4->sin_addr; + else + ip->ip_src = target4->sin_addr; + ip4_fix_checksum(ip); + } + else if (ip6 && target6) + { + nport = target6->sin6_port; + if (bOutbound) + ip6->ip6_dst = target6->sin6_addr; + else + ip6->ip6_src = target6->sin6_addr; + } + else + return; + if (nport) + { + if (tcphdr) + { + if (bOutbound) + tcphdr->th_dport = nport; + else + tcphdr->th_sport = nport; + } + if (udphdr) + { + if (bOutbound) + udphdr->uh_dport = nport; + else + udphdr->uh_sport = nport; + } + } +} + void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr) { diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index b152d2b..f321d56 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -211,6 +211,7 @@ typedef struct #define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;} uint8_t autottl_guess(uint8_t ttl, const autottl *attl); +void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6); void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr); void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr); diff --git a/nfq/desync.c b/nfq/desync.c index 0bfc28f..2d339ca 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -1511,6 +1511,7 @@ static void packet_debug(bool replay, uint8_t proto, const struct ip *ip, const } } + static uint8_t dpi_desync_packet_play(bool replay, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt) { struct ip *ip; diff --git a/nfq/helpers.c b/nfq/helpers.c index efabfd7..29ac6c8 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -136,6 +136,51 @@ void print_sockaddr(const struct sockaddr *sa) printf("%s", ip_port); } +bool pton4_port(const char *s, struct sockaddr_in *sa) +{ + char ip[16],*p; + size_t l; + unsigned int u; + + p = strchr(s,':'); + if (!p) return false; + l = p-s; + if (l<7 || l>15) return false; + memcpy(ip,s,l); + ip[l]=0; + p++; + + sa->sin_family = AF_INET; + if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; + sa->sin_port = htons((uint16_t)u); + + return true; +} +bool pton6_port(const char *s, struct sockaddr_in6 *sa) +{ + char ip[40],*p; + size_t l; + unsigned int u; + + if (*s++!='[') return false; + p = strchr(s,']'); + if (!p || p[1]!=':') return false; + l = p-s; + if (l<2 || l>39) return false; + p+=2; + memcpy(ip,s,l); + ip[l]=0; + + sa->sin6_family = AF_INET6; + if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false; + sa->sin6_port = htons((uint16_t)u); + sa->sin6_flowinfo = 0; + sa->sin6_scope_id = 0; + + return true; +} + + void dbgprint_socket_buffers(int fd) { if (params.debug) diff --git a/nfq/helpers.h b/nfq/helpers.h index 2f630b9..fdbbe9d 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -19,6 +19,8 @@ bool append_to_list_file(const char *filename, const char *s); void print_sockaddr(const struct sockaddr *sa); void ntop46(const struct sockaddr *sa, char *str, size_t len); void ntop46_port(const struct sockaddr *sa, char *str, size_t len); +bool pton4_port(const char *s, struct sockaddr_in *sa); +bool pton6_port(const char *s, struct sockaddr_in6 *sa); bool seq_within(uint32_t s, uint32_t s1, uint32_t s2); diff --git a/nfq/nfqws b/nfq/nfqws new file mode 120000 index 0000000..3c518b9 --- /dev/null +++ b/nfq/nfqws @@ -0,0 +1 @@ +../binaries/my/nfqws \ No newline at end of file diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 3a62d18..fdbbcb9 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -29,6 +29,12 @@ #include #include +#ifdef __CYGWIN__ +#include +#include "win.h" +#endif + + #ifdef __linux__ #include #define NF_DROP 0 @@ -41,7 +47,9 @@ #define CTRACK_T_UDP 60 struct params_s params; - +#ifdef __CYGWIN__ +bool bQuit=false; +#endif static bool bHup = false; static void onhup(int sig) @@ -421,6 +429,11 @@ static int win_main(const char *windivert_filter) DLOG("windivert: ignoring too large packet\n") continue; // too large packet } + else if (errno==EINTR) + { + DLOG("QUIT requested\n") + break; + } fprintf(stderr, "windivert: recv failed. errno %d\n", errno); break; } @@ -707,6 +720,12 @@ static bool wf_make_filter( return true; } +bool WinSrvInstall(const char *name, const char *binpath) +{ + return false; +} + + #endif @@ -809,13 +828,21 @@ static void exithelp_clean(void) int main(int argc, char **argv) { +#ifdef __CYGWIN__ + if (service_run(argc, argv)) + { + // we were running as service. now exit. + return 0; + } +#endif + int result, v; int option_index = 0; bool daemon = false; char pidfile[256]; #ifdef __CYGWIN__ 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; + bool wf_ipv4=true, wf_ipv6=true, srv_inst=false, srv_del=false; unsigned int IfIdx=0, SubIfIdx=0; *windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0; #endif @@ -1431,7 +1458,6 @@ int main(int argc, char **argv) strncpy(wf_save_file, optarg, sizeof(wf_save_file)); wf_save_file[sizeof(wf_save_file) - 1] = '\0'; break; - #endif } } @@ -1473,7 +1499,7 @@ int main(int argc, char **argv) else { fprintf(stderr, "windivert filter: could not save raw filter to %s\n", wf_save_file); - exit_clean(0); + exit_clean(1); } } #endif @@ -1522,6 +1548,10 @@ int main(int argc, char **argv) ex: rawsend_cleanup(); cleanup_params(); +#ifdef __CYGWIN__ + service_stopped(); + +#endif return result; exiterr: result = 1; diff --git a/nfq/nfqws.h b/nfq/nfqws.h index 6f70f09..86aa882 100644 --- a/nfq/nfqws.h +++ b/nfq/nfqws.h @@ -1 +1,8 @@ #pragma once + +#include + +#ifdef __CYGWIN__ +extern bool bQuit; +#endif +int main(int argc, char *argv[]); diff --git a/nfq/win.c b/nfq/win.c new file mode 100644 index 0000000..7d71ee6 --- /dev/null +++ b/nfq/win.c @@ -0,0 +1,94 @@ +#ifdef __CYGWIN__ + +#include +#include +#include +#include + +#include "win.h" +#include "nfqws.h" + +#define SERVICE_NAME "winws" + +static SERVICE_STATUS ServiceStatus; +static SERVICE_STATUS_HANDLE hStatus = NULL; +static int service_argc = 0; +static char **service_argv = NULL; + +void service_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))); + +bool service_run(int argc, char *argv[]) +{ + int i; + + SERVICE_TABLE_ENTRY ServiceTable[] = { + {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, + {NULL, NULL} + }; + + service_argc = argc; + service_argv = argv; + + return StartServiceCtrlDispatcherA(ServiceTable); +} + +static void service_set_status(DWORD state) +{ + ServiceStatus.dwCurrentState = state; + SetServiceStatus(hStatus, &ServiceStatus); +} +void service_stopped() +{ + service_set_status(SERVICE_STOPPED); +} + +// Control handler function +void service_controlhandler(DWORD request) +{ + switch (request) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + bQuit = true; + service_set_status(SERVICE_STOP_PENDING); + break; + default: + // Report current status + SetServiceStatus(hStatus, &ServiceStatus); + break; + } + return; +} + +void service_main(int argc __attribute__((unused)), + char *argv[] __attribute__((unused))) +{ + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 1; + ServiceStatus.dwWaitHint = 0; + + hStatus = RegisterServiceCtrlHandlerA( + SERVICE_NAME, + (LPHANDLER_FUNCTION)service_controlhandler); + if (hStatus == (SERVICE_STATUS_HANDLE)0) + { + // Registering Control Handler failed + return; + } + + SetServiceStatus(hStatus, &ServiceStatus); + + // Calling main with saved argc & argv + ServiceStatus.dwWin32ExitCode = (DWORD)main(service_argc, service_argv); + + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(hStatus, &ServiceStatus); + return; +} + + +#endif diff --git a/nfq/win.h b/nfq/win.h new file mode 100644 index 0000000..097442b --- /dev/null +++ b/nfq/win.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __CYGWIN__ + +#include + +bool service_run(); +void service_stopped(); + +#endif +