From 76668991c590854232cfc3a8dbea06cba1973c32 Mon Sep 17 00:00:00 2001 From: ruti <> Date: Sun, 18 Feb 2024 23:20:52 +0300 Subject: [PATCH] Windows support --- Makefile | 5 ++- conev.c | 6 ++-- conev.h | 33 ++++++++++------- desync.c | 68 +++++++++++++++++++---------------- error.c | 46 ++++++++++++++++++++++++ error.h | 4 +++ main.c | 88 ++++++++++++++------------------------------- packets.c | 17 +++++++-- params.h | 7 +++- proxy.c | 102 +++++++++++++++++++++++++++++++++-------------------- proxy.h | 7 +++- readme.txt | 10 +++--- 12 files changed, 236 insertions(+), 157 deletions(-) create mode 100644 error.c create mode 100644 error.h diff --git a/Makefile b/Makefile index 9d1bfb0..bb776f0 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ TARGET = ciadpi CC ?= gcc CFLAGS += -std=c99 -O2 -D_XOPEN_SOURCE=500 -SOURCES = packets.c main.c conev.c proxy.c desync.c +SOURCES = packets.c main.c conev.c proxy.c desync.c error.c all: $(CC) $(CFLAGS) $(SOURCES) -I . -o $(TARGET) +windows: + $(CC) $(CFLAGS) $(SOURCES) -I . -lws2_32 -o $(TARGET).exe + clean: rm -f $(TARGET) *.o diff --git a/conev.c b/conev.c index 8436d22..21e9981 100644 --- a/conev.c +++ b/conev.c @@ -1,10 +1,10 @@ #define CONEV_H #include +#include #include #include #include -#include struct poolhd *init_pool(int count) @@ -68,7 +68,7 @@ struct eval *add_event(struct poolhd *pool, enum eid type, struct pollfd *pfd = &(pool->pevents[pool->count]); pfd->fd = fd; - pfd->events = POLLIN | POLLERR | POLLRDHUP | e; + pfd->events = POLLIN | e; pfd->revents = 0; #endif @@ -181,7 +181,7 @@ struct eval *next_event(struct poolhd *pool, int *offs, int *typel) for (int i = *offs; ; i--) { if (i < 0) { if (poll(pool->pevents, pool->count, -1) <= 0) { - perror("poll"); + uniperror("poll"); return 0; } i = pool->count - 1; diff --git a/conev.h b/conev.h index 90e99f4..15be03f 100644 --- a/conev.h +++ b/conev.h @@ -1,22 +1,31 @@ #include -#include #ifndef __linux__ -#define NOEPOLL + #define NOEPOLL #endif -#ifndef NOEPOLL -#include -#define POLLIN EPOLLIN -#define POLLOUT EPOLLOUT -#define POLLERR EPOLLERR -#define POLLHUP EPOLLHUP -#define POLLRDHUP EPOLLRDHUP +#ifdef _WIN32 + #include + #define poll(fds, cnt, to) WSAPoll(fds, cnt, to) + #define close(fd) closesocket(fd) #else -#include -#ifndef POLLRDHUP -#define POLLRDHUP POLLHUP + #include + #include + + #ifndef NOEPOLL + #include + #define POLLIN EPOLLIN + #define POLLOUT EPOLLOUT + #define POLLERR EPOLLERR + #define POLLHUP EPOLLHUP + #define POLLRDHUP EPOLLRDHUP + #else + #include + #endif #endif + +#ifndef POLLRDHUP + #define POLLRDHUP POLLHUP #endif enum eid { diff --git a/desync.c b/desync.c index ea38682..5f16c9c 100644 --- a/desync.c +++ b/desync.c @@ -1,30 +1,37 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#ifdef __linux__ -#include -#define _sendfile(outfd, infd, start, len) sendfile(outfd, infd, start, len) -#else -#include -#define _sendfile(outfd, infd, start, len) sendfile(infd, outfd, start, len, 0, 0) -#endif +#ifndef _WIN32 + #include + #include + #include + #include + #include + #include + #include + + #ifdef __linux__ + #include + #define _sendfile(outfd, infd, start, len) sendfile(outfd, infd, start, len) + #else + #include + #define _sendfile(outfd, infd, start, len) sendfile(infd, outfd, start, len, 0, 0) + #endif -#ifdef MFD_CLOEXEC -#include -#define memfd_create(name, flags) syscall(__NR_memfd_create, name, flags); + #ifdef MFD_CLOEXEC + #include + #define memfd_create(name, flags) syscall(__NR_memfd_create, name, flags); + #else + #define memfd_create(name, flags) fileno(tmpfile()) + #endif #else -#define memfd_create(name, flags) fileno(tmpfile()) + #include + #include #endif #include #include +#include static inline int get_family(struct sockaddr *dst) @@ -46,20 +53,20 @@ int setttl(int fd, int ttl, int family) { if (family == AF_INET) { if (setsockopt(fd, IPPROTO_IP, - IP_TTL, &_ttl, sizeof(_ttl)) < 0) { - perror("setsockopt IP_TTL"); + IP_TTL, (char *)&_ttl, sizeof(_ttl)) < 0) { + uniperror("setsockopt IP_TTL"); return -1; } } else if (setsockopt(fd, IPPROTO_IPV6, - IPV6_UNICAST_HOPS, &_ttl, sizeof(_ttl)) < 0) { - perror("setsockopt IPV6_UNICAST_HOPS"); + IPV6_UNICAST_HOPS, (char *)&_ttl, sizeof(_ttl)) < 0) { + uniperror("setsockopt IPV6_UNICAST_HOPS"); return -1; } return 0; } - +#ifndef _WIN32 int fake_attack(int sfd, char *buffer, size_t n, int cnt, int pos, int fa) { @@ -113,7 +120,7 @@ int fake_attack(int sfd, char *buffer, close(ffd); return status; } - +#endif int disorder_attack(int sfd, char *buffer, ssize_t n, int pos, int fa) @@ -123,14 +130,14 @@ int disorder_attack(int sfd, char *buffer, return -1; } if (send(sfd, buffer, pos, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } if (setttl(sfd, params.def_ttl, fa) < 0) { return -1; } if (send(sfd, buffer + pos, n - pos, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } return 0; @@ -190,25 +197,26 @@ int desync(int sfd, char *buffer, size_t bfsize, (!type && params.de_known)) { if (send(sfd, buffer, n, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } } else switch (params.attack) { + #ifndef _WIN32 case DESYNC_FAKE: return fake_attack(sfd, buffer, n, type, pos, fa); - + #endif case DESYNC_DISORDER: return disorder_attack(sfd, buffer, n, pos, fa); case DESYNC_SPLIT: default: if (send(sfd, buffer, pos, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } if (send(sfd, buffer + pos, n - pos, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } } diff --git a/error.c b/error.c new file mode 100644 index 0000000..d3ca8ff --- /dev/null +++ b/error.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +int unie(int e) +{ + #ifdef _WIN32 + switch (e) { + case WSAEWOULDBLOCK: + return EAGAIN; + case WSAETIMEDOUT: + return ETIMEDOUT; + case WSAENETUNREACH: + return ENETUNREACH; + case WSAEHOSTUNREACH: + return EHOSTUNREACH; + case WSAECONNREFUSED: + return ECONNREFUSED; + } + #endif + return e; +} + +int get_e() +{ + #ifdef _WIN32 + int e = WSAGetLastError(); + return unie(e); + #else + return errno; + #endif +} + +void uniperror(char *str) +{ + #ifdef _WIN32 + int e = WSAGetLastError(); + fprintf(stderr, "%s: %d\n", str, e); + #else + perror(str); + #endif +} diff --git a/error.h b/error.h new file mode 100644 index 0000000..bc10868 --- /dev/null +++ b/error.h @@ -0,0 +1,4 @@ +int unie(int e); +void uniperror(char *str); +int get_e(); +void uniperror(char *str); diff --git a/main.c b/main.c index edc27eb..8c849f2 100644 --- a/main.c +++ b/main.c @@ -9,16 +9,21 @@ #include #include #include +#include -#include -#include -#include -#include +#ifndef _WIN32 + #include + #include + #include + #include + #define FAKE_SUPPORT 1 +#else + #include + #define close(fd) closesocket(fd) +#endif -#define FAKE_SUPPORT 1 - -#define VERSION 3 +#define VERSION 4 struct packet fake_tls = { @@ -57,8 +62,6 @@ struct params params = { const char help_text[] = { " -i, --ip, Listening IP, default 0.0.0.0\n" " -p, --port Listening port, default 1080\n" - " -D, --daemon Daemonize\n" - " -f, --pidfile Write pid to file\n" " -c, --max-conn Connection count limit, default 512\n" " -N, --no-domain Deny domain resolving\n" " -I --conn-ip Connection binded IP, default ::\n" @@ -87,12 +90,10 @@ const char help_text[] = { const struct option options[] = { - {"daemon", 0, 0, 'D'}, {"no-domain", 0, 0, 'N'}, {"no-ipv6", 0, 0, 'X'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, - {"pidfile", 1, 0, 'f'}, {"ip", 1, 0, 'i'}, {"port", 1, 0, 'p'}, {"conn-ip", 1, 0, 'I'}, @@ -152,29 +153,6 @@ char *ftob(char *name, ssize_t *sl) } -void daemonize(void) -{ - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - else if (pid) { - exit(0); - } - if (setsid() < 0) { - exit(1); - } - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - open("/dev/null", O_RDWR); - dup(0); - dup(0); -} - - int get_addr(char *str, struct sockaddr_ina *addr) { struct addrinfo hints = {0}, *res = 0; @@ -201,12 +179,12 @@ int get_default_ttl() socklen_t tsize = sizeof(orig_ttl); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); + uniperror("socket"); return -1; } if (getsockopt(fd, IPPROTO_IP, IP_TTL, (char *)&orig_ttl, &tsize) < 0) { - perror("getsockopt IP_TTL"); + uniperror("getsockopt IP_TTL"); } close(fd); return orig_ttl; @@ -215,6 +193,14 @@ int get_default_ttl() int main(int argc, char **argv) { + #ifdef _WIN32 + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2, 2), &wsa)) { + uniperror("WSAStartup"); + return -1; + } + #endif struct sockaddr_ina s = { .in = { .sin_family = AF_INET, @@ -251,9 +237,6 @@ int main(int argc, char **argv) argc, argv, opt, options, 0)) != -1) { switch (rez) { - case 'D': - daemon = 1; - break; case 'N': params.resolve = 0; break; @@ -266,9 +249,6 @@ int main(int argc, char **argv) case 'v': printf("%d\n", VERSION); return 0; - case 'f': - pidfile = optarg; - break; case 'i': if (get_addr(optarg, &s) < 0) @@ -458,28 +438,14 @@ int main(int argc, char **argv) if (b.sa.sa_family != AF_INET6) { params.ipv6 = 0; } - - FILE *file; - if (pidfile) { - file = fopen(pidfile, "w"); - if (!file) { - perror("fopen"); - return -1; - } - } - if (daemon) { - daemonize(); - } - if (pidfile) { - fprintf(file, "%d", getpid()); - fclose(file); - } - if (!params.def_ttl && params.attack != DESYNC_NONE) { if ((params.def_ttl = get_default_ttl()) < 1) { return -1; } } - - return listener(s); + int status = listener(s); + #ifdef _WIN32 + WSACleanup(); + #endif + return status; } diff --git a/packets.c b/packets.c index 6d36889..e388854 100644 --- a/packets.c +++ b/packets.c @@ -6,7 +6,12 @@ #include #include #include -#include + +#ifdef _WIN32 + #include +#else + #include +#endif #define ANTOHS(data, i) \ (uint16_t)((data[i] << 8) + (uint8_t)data[i + 1]) @@ -167,8 +172,14 @@ int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port) if (!(isdigit(*(l_end - 1)))) h_end = 0; - else - h_end = memrchr(host, ':', l_end - host); + else { + char *h = host; + h_end = 0; + do { + h = memchr(h, ':', l_end - h); + if (h) h_end = h; + } while (h); + } if (!h_end) { if (port) *port = 80; diff --git a/params.h b/params.h index e943196..8659625 100644 --- a/params.h +++ b/params.h @@ -1,5 +1,10 @@ #include -#include + +#ifdef _WIN32 + #include +#else + #include +#endif enum demode { DESYNC_NONE, diff --git a/proxy.c b/proxy.c index aa50871..3591b78 100644 --- a/proxy.c +++ b/proxy.c @@ -10,15 +10,23 @@ #include #include #include +#include -#include -#include -#include - -#include -#include -#include -#include +#ifdef _WIN32 + #include + #include + + #define close(fd) closesocket(fd) +#else + #include + #include + #include + + #include + #include + #include + #include +#endif int NOT_EXIT = 1; @@ -60,9 +68,17 @@ static inline int nb_socket(int domain, int type) int fd = socket(domain, type, 0); #endif if (fd < 0) { - perror("socket"); + uniperror("socket"); return -1; } + #ifdef _WIN32 + unsigned long mode = 1; + if (ioctlsocket(fd, FIONBIO, &mode) < 0) { + uniperror("ioctlsocket"); + close(fd); + return -1; + } + #else #ifndef __linux__ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { perror("fcntl"); @@ -70,6 +86,7 @@ static inline int nb_socket(int domain, int type) return -1; } #endif + #endif return fd; } @@ -114,7 +131,7 @@ int auth_socks5(int fd, char *buffer, ssize_t n) } buffer[1] = c; if (send(fd, buffer, 2, 0) < 0) { - perror("send"); + uniperror("send"); return -1; } return c != S_AUTH_BAD ? 0 : -1; @@ -140,7 +157,7 @@ int resp_error(int fd, int e, int flag) return send(fd, (char *)&s4r, sizeof(s4r), 0); } else if (flag == FLAG_S5) { - switch (e) { + switch (unie(e)) { case 0: e = S_ER_OK; break; case ECONNREFUSED: @@ -260,21 +277,21 @@ int create_conn(struct poolhd *pool, } int sfd = nb_socket(addr.sa.sa_family, SOCK_STREAM); if (sfd < 0) { - perror("socket"); + uniperror("socket"); return -1; } if (addr.sa.sa_family == AF_INET6) { int no = 0; if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&no, sizeof(no))) { - perror("setsockopt IPV6_V6ONLY"); + uniperror("setsockopt IPV6_V6ONLY"); close(sfd); return -1; } } if (bind(sfd, (struct sockaddr *)¶ms.baddr, sizeof(params.baddr)) < 0) { - perror("bind"); + uniperror("bind"); close(sfd); return -1; } @@ -282,7 +299,7 @@ int create_conn(struct poolhd *pool, int syn_count = 1; if (setsockopt(sfd, IPPROTO_TCP, TCP_SYNCNT, (char *)&syn_count, sizeof(syn_count))) { - perror("setsockopt TCP_SYNCNT"); + uniperror("setsockopt TCP_SYNCNT"); close(sfd); return -1; } @@ -290,13 +307,14 @@ int create_conn(struct poolhd *pool, int one = 1; if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one))) { - perror("setsockopt TCP_NODELAY"); + uniperror("setsockopt TCP_NODELAY"); close(sfd); return -1; } int status = connect(sfd, &addr.sa, sizeof(addr)); - if (status < 0 && errno != EINPROGRESS) { - perror("connect"); + if (status < 0 && + get_e() != EINPROGRESS && get_e() != EAGAIN) { + uniperror("connect"); close(sfd); return -1; } @@ -320,7 +338,7 @@ static inline int on_request(struct poolhd *pool, struct eval *val, ssize_t n = recv(val->fd, buffer, bfsize, 0); if (n < 1) { - if (n) perror("ss recv"); + if (n) uniperror("ss recv"); return -1; } if (*buffer == S_VER5) { @@ -354,7 +372,7 @@ static inline int on_request(struct poolhd *pool, struct eval *val, } if (error) { if (resp_error(val->fd, error, FLAG_S4) < 0) - perror("send"); + uniperror("send"); return -1; } } @@ -380,15 +398,21 @@ static inline int on_accept(struct poolhd *pool, struct eval *val) int c = accept(val->fd, &client.sa, &len); #endif if (c < 0) { - if (errno == EAGAIN || - errno == EINPROGRESS) + if (get_e() == EAGAIN || + get_e() == EINPROGRESS) break; - perror("accept"); + uniperror("accept"); return -1; } #ifndef __linux__ + #ifdef _WIN32 + unsigned long mode = 1; + if (ioctlsocket(c, FIONBIO, &mode) < 0) { + uniperror("ioctlsocket"); + #else if (fcntl(c, F_SETFL, O_NONBLOCK) < 0) { perror("fcntl"); + #endif close(c); continue; } @@ -396,7 +420,7 @@ static inline int on_accept(struct poolhd *pool, struct eval *val) int one = 1; if (setsockopt(c, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one))) { - perror("setsockopt TCP_NODELAY"); + uniperror("setsockopt TCP_NODELAY"); close(c); continue; } @@ -419,13 +443,13 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, if (e) { if (getsockopt(val->fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)) { - perror("getsockopt SO_ERROR"); + uniperror("getsockopt SO_ERROR"); return -1; } } if (resp_error(val->pair->fd, error, val->pair->flag) < 0) { - perror("send"); + uniperror("send"); return -1; } if (e) { @@ -440,7 +464,7 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, else { ssize_t n = recv(val->fd, buffer, bfsize, 0); if (n <= 0) { - if (n) perror("recv data"); + if (n) uniperror("recv data"); return -1; } if (desync(val->pair->fd, buffer, bfsize, @@ -466,8 +490,8 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, n = val->size - val->offset; ssize_t sn = send(pair->fd, val->tmpbuf + val->offset, n, 0); if (sn != n) { - if (sn < 0 && errno != EAGAIN) { - perror("send"); + if (sn < 0 && get_e() != EAGAIN) { + uniperror("send"); return -1; } if (sn > 0) @@ -484,17 +508,17 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, } do { n = recv(val->fd, buffer, bfsize, 0); - if (n < 0 && errno == EAGAIN) + if (n < 0 && get_e() == EAGAIN) break; if (n < 1) { - if (n) perror("recv"); + if (n) uniperror("recv"); return -1; } ssize_t sn = send(pair->fd, buffer, n, 0); if (sn != n) { if (sn < 0) { - if (errno != EAGAIN) { - perror("send"); + if (get_e() != EAGAIN) { + uniperror("send"); return -1; } sn = 0; @@ -541,9 +565,9 @@ int big_loop(int srvfd) while (NOT_EXIT) { val = next_event(pool, &i, &etype); if (!val) { - if (errno == EINTR) + if (get_e() == EINTR) continue; - perror("(e)poll"); + uniperror("(e)poll"); break; } LOG(LOG_L, "new event: fd: %d, evt: %s\n", val->fd, eid_name[val->type]); @@ -600,23 +624,23 @@ int listener(struct sockaddr_ina srv) int srvfd = nb_socket(srv.sa.sa_family, SOCK_STREAM); if (srvfd < 0) { - perror("socket"); + uniperror("socket"); return -1; } int opt = 1; if (setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) == -1) { - perror("setsockopt"); + uniperror("setsockopt"); close(srvfd); return -1; } if (bind(srvfd, &srv.sa, sizeof(srv)) < 0) { - perror("bind"); + uniperror("bind"); close(srvfd); return -1; } if (listen(srvfd, 10)) { - perror("listen"); + uniperror("listen"); close(srvfd); return -1; } diff --git a/proxy.h b/proxy.h index e4a928a..c9ea85d 100644 --- a/proxy.h +++ b/proxy.h @@ -1,5 +1,10 @@ #include -#include + +#ifdef _WIN32 + #include +#else + #include +#endif struct sockaddr_ina { union { diff --git a/readme.txt b/readme.txt index 0d74f0d..d359860 100644 --- a/readme.txt +++ b/readme.txt @@ -5,13 +5,9 @@ $ ./ciadpi --method disorder --split-pos 3 --port 1080 Чуть более подробный текст "--help": -i, --ip - Прослушиваемый IP, по умолчанию 0.0.0.0 + Прослушиваемый IP, по умолчанию 0.0.0.0 -p, --port - Прослушиваемый порт, по умолчанию 1080 --D, --daemon - Запуск в режиме демона --f, --pidfile - Записать PID в указанный файл + Прослушиваемый порт, по умолчанию 1080 -c, --max-conn Максимальное количество клиентских подключений, по умолчанию 512 -I --conn-ip @@ -30,8 +26,10 @@ $ ./ciadpi --method disorder --split-pos 3 --port 1080 Разбить первый запрос на два по определённому смещению disorder: Как split, но части отправляются в обратном порядке + ! Поведение в Windows отлично: сначала отправляется вторая часть, затем целый запрос fake: Как disorder, только перед первым запросом отправляется поддельный такого же размера (т.е. равное значению split-pos) + ! В Windows не поддерживается -s, --split-pos Смещение, по которому будет разбит запрос, по умолчанию 3