winws: windows service support

This commit is contained in:
bol-van 2024-04-30 15:35:20 +03:00
parent 9eded3d3ce
commit 9df7574b2b
20 changed files with 291 additions and 8 deletions

Binary file not shown.

View File

@ -0,0 +1,6 @@
ej.ru
bbc.com
static.rutracker.cc
nnmclub.to
hdrezka.ag
rutracker.org

View File

@ -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: 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 start "zapret: quic" "%~dp0winws.exe" --wf-udp=443 --dpi-desync=fake --dpi-desync-repeats=11

View File

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

View File

@ -0,0 +1,7 @@
call :srvdel winws1
rem call :srvdel winws2
goto :eof
:srvdel
net stop %1
sc delete %1

View File

@ -0,0 +1,2 @@
sc start winws1
rem sc start winws2

View File

@ -0,0 +1,2 @@
net stop winws1
rem net stop winws2

View File

@ -89,6 +89,7 @@ badseq может работать только на https и не работа
8) Обеспечьте удобную загрузку обхода блокировок. 8) Обеспечьте удобную загрузку обхода блокировок.
Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя. Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя.
Последний вариант разделяется на запуск через планировщик задач и через службы windows.
Если хотите ручной запуск, скопируйте preset_russia.cmd в preset_my.cmd и адаптируйте его под ваши параметра запуска. Если хотите ручной запуск, скопируйте preset_russia.cmd в preset_my.cmd и адаптируйте его под ваши параметра запуска.
Потом можно создать ярлык на рабочем столе на preset_my.cmd. Не забудьте, что требуется запускать от имени администратора. Потом можно создать ярлык на рабочем столе на preset_my.cmd. Не забудьте, что требуется запускать от имени администратора.
@ -100,6 +101,8 @@ badseq может работать только на https и не работа
для поддержки нескольких задач : winws1,winws2,winws3. для поддержки нескольких задач : winws1,winws2,winws3.
После создания задач запустите их. Проверьте, что обход встает после перезагрузки windows. После создания задач запустите их. Проверьте, что обход встает после перезагрузки windows.
Аналогично настраиваются и службы windows. Смотрите service_*.cmd
9) Если ломаются отдельные незаблокированные ресурсы, используйте хост-листы. 9) Если ломаются отдельные незаблокированные ресурсы, используйте хост-листы.
Где они будут находиться - решайте сами. Где они будут находиться - решайте сами.
Параметры управления хост-листами точно такие же, как в *nix. Параметры управления хост-листами точно такие же, как в *nix.

View File

@ -114,13 +114,16 @@ cygwin для обычной работы winws не нужен. Разве чт
автозапуск winws автозапуск winws
---------------- ----------------
Для запуска winws вместе с windows воспользуйтесь планировщиком задач windows. Для запуска winws вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Удобнее всего создавать задачи и управлять ими через консольную программу schtasks.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории binaries/win64/winws подготовлены файлы task_*.cmd . В директории binaries/win64/winws подготовлены файлы task_*.cmd .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной %WINWS1%. В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной %WINWS1%.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач winws1,winws2,winws3,... для задач winws1,winws2,winws3,...
Аналогично настраивается вариант запуска через службы windows. Смотрите service_*.cmd.
Все батники требуется запускать от имени администратора. Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком taskschd.msc Управлять задачами можно так же из графической программы управления планировщиком taskschd.msc

View File

@ -12,6 +12,7 @@
#include "darkmagic.h" #include "darkmagic.h"
#include "helpers.h" #include "helpers.h"
#include "params.h" #include "params.h"
#include "nfqws.h"
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) 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; DWORD rd;
char c; char c;
if (bQuit)
{
errno=EINTR;
return false;
}
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, NULL, &ovl)) if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, NULL, &ovl))
{ {
*len = recv_len; *len = recv_len;
@ -1028,7 +1034,15 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
{ {
case ERROR_IO_PENDING: case ERROR_IO_PENDING:
// make signals working // 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)) if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE))
continue; continue;
*len = rd; *len = rd;
@ -1439,6 +1453,48 @@ uint8_t autottl_guess(uint8_t ttl, const autottl *attl)
return fake; 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) void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr)
{ {

View File

@ -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;} #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); 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_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); void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);

View File

@ -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) 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; struct ip *ip;

View File

@ -136,6 +136,51 @@ void print_sockaddr(const struct sockaddr *sa)
printf("%s", ip_port); 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) void dbgprint_socket_buffers(int fd)
{ {
if (params.debug) if (params.debug)

View File

@ -19,6 +19,8 @@ bool append_to_list_file(const char *filename, const char *s);
void print_sockaddr(const struct sockaddr *sa); void print_sockaddr(const struct sockaddr *sa);
void ntop46(const struct sockaddr *sa, char *str, size_t len); void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(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); bool seq_within(uint32_t s, uint32_t s1, uint32_t s2);

1
nfq/nfqws Symbolic link
View File

@ -0,0 +1 @@
../binaries/my/nfqws

View File

@ -29,6 +29,12 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <netinet/in.h> #include <netinet/in.h>
#ifdef __CYGWIN__
#include <windows.h>
#include "win.h"
#endif
#ifdef __linux__ #ifdef __linux__
#include <libnetfilter_queue/libnetfilter_queue.h> #include <libnetfilter_queue/libnetfilter_queue.h>
#define NF_DROP 0 #define NF_DROP 0
@ -41,7 +47,9 @@
#define CTRACK_T_UDP 60 #define CTRACK_T_UDP 60
struct params_s params; struct params_s params;
#ifdef __CYGWIN__
bool bQuit=false;
#endif
static bool bHup = false; static bool bHup = false;
static void onhup(int sig) static void onhup(int sig)
@ -421,6 +429,11 @@ static int win_main(const char *windivert_filter)
DLOG("windivert: ignoring too large packet\n") DLOG("windivert: ignoring too large packet\n")
continue; // too large packet continue; // too large packet
} }
else if (errno==EINTR)
{
DLOG("QUIT requested\n")
break;
}
fprintf(stderr, "windivert: recv failed. errno %d\n", errno); fprintf(stderr, "windivert: recv failed. errno %d\n", errno);
break; break;
} }
@ -707,6 +720,12 @@ static bool wf_make_filter(
return true; return true;
} }
bool WinSrvInstall(const char *name, const char *binpath)
{
return false;
}
#endif #endif
@ -809,13 +828,21 @@ static void exithelp_clean(void)
int main(int argc, char **argv) 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 result, v;
int option_index = 0; int option_index = 0;
bool daemon = false; bool daemon = false;
char pidfile[256]; char pidfile[256];
#ifdef __CYGWIN__ #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]; 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; 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; *windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0;
#endif #endif
@ -1431,7 +1458,6 @@ int main(int argc, char **argv)
strncpy(wf_save_file, optarg, sizeof(wf_save_file)); strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0'; wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break; break;
#endif #endif
} }
} }
@ -1473,7 +1499,7 @@ int main(int argc, char **argv)
else else
{ {
fprintf(stderr, "windivert filter: could not save raw filter to %s\n", wf_save_file); fprintf(stderr, "windivert filter: could not save raw filter to %s\n", wf_save_file);
exit_clean(0); exit_clean(1);
} }
} }
#endif #endif
@ -1522,6 +1548,10 @@ int main(int argc, char **argv)
ex: ex:
rawsend_cleanup(); rawsend_cleanup();
cleanup_params(); cleanup_params();
#ifdef __CYGWIN__
service_stopped();
#endif
return result; return result;
exiterr: exiterr:
result = 1; result = 1;

View File

@ -1 +1,8 @@
#pragma once #pragma once
#include <stdbool.h>
#ifdef __CYGWIN__
extern bool bQuit;
#endif
int main(int argc, char *argv[]);

94
nfq/win.c Normal file
View File

@ -0,0 +1,94 @@
#ifdef __CYGWIN__
#include <unistd.h>
#include <signal.h>
#include <windows.h>
#include <stdio.h>
#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

11
nfq/win.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __CYGWIN__
#include <stdbool.h>
bool service_run();
void service_stopped();
#endif