Windows support

This commit is contained in:
ruti 2024-02-18 23:20:52 +03:00
parent 49828467a4
commit 76668991c5
12 changed files with 236 additions and 157 deletions

View File

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

View File

@ -1,10 +1,10 @@
#define CONEV_H
#include <conev.h>
#include <error.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
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;

33
conev.h
View File

@ -1,22 +1,31 @@
#include <stdint.h>
#include <netinet/in.h>
#ifndef __linux__
#define NOEPOLL
#define NOEPOLL
#endif
#ifndef NOEPOLL
#include <sys/epoll.h>
#define POLLIN EPOLLIN
#define POLLOUT EPOLLOUT
#define POLLERR EPOLLERR
#define POLLHUP EPOLLHUP
#define POLLRDHUP EPOLLRDHUP
#ifdef _WIN32
#include <ws2tcpip.h>
#define poll(fds, cnt, to) WSAPoll(fds, cnt, to)
#define close(fd) closesocket(fd)
#else
#include <sys/poll.h>
#ifndef POLLRDHUP
#define POLLRDHUP POLLHUP
#include <netinet/in.h>
#include <unistd.h>
#ifndef NOEPOLL
#include <sys/epoll.h>
#define POLLIN EPOLLIN
#define POLLOUT EPOLLOUT
#define POLLERR EPOLLERR
#define POLLHUP EPOLLHUP
#define POLLRDHUP EPOLLRDHUP
#else
#include <sys/poll.h>
#endif
#endif
#ifndef POLLRDHUP
#define POLLRDHUP POLLHUP
#endif
enum eid {

View File

@ -1,30 +1,37 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/mman.h>
#ifdef __linux__
#include <sys/sendfile.h>
#define _sendfile(outfd, infd, start, len) sendfile(outfd, infd, start, len)
#else
#include <sys/uio.h>
#define _sendfile(outfd, infd, start, len) sendfile(infd, outfd, start, len, 0, 0)
#endif
#ifndef _WIN32
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/mman.h>
#ifdef __linux__
#include <sys/sendfile.h>
#define _sendfile(outfd, infd, start, len) sendfile(outfd, infd, start, len)
#else
#include <sys/uio.h>
#define _sendfile(outfd, infd, start, len) sendfile(infd, outfd, start, len, 0, 0)
#endif
#ifdef MFD_CLOEXEC
#include <sys/syscall.h>
#define memfd_create(name, flags) syscall(__NR_memfd_create, name, flags);
#ifdef MFD_CLOEXEC
#include <sys/syscall.h>
#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 <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <params.h>
#include <packets.h>
#include <error.h>
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;
}
}

46
error.c Normal file
View File

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef _WIN32
#include <winsock2.h>
#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
}

4
error.h Normal file
View File

@ -0,0 +1,4 @@
int unie(int e);
void uniperror(char *str);
int get_e();
void uniperror(char *str);

88
main.c
View File

@ -9,16 +9,21 @@
#include <params.h>
#include <proxy.h>
#include <packets.h>
#include <error.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#ifndef _WIN32
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#define FAKE_SUPPORT 1
#else
#include <ws2tcpip.h>
#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, <ip> Listening IP, default 0.0.0.0\n"
" -p, --port <num> Listening port, default 1080\n"
" -D, --daemon Daemonize\n"
" -f, --pidfile <file> Write pid to file\n"
" -c, --max-conn <count> Connection count limit, default 512\n"
" -N, --no-domain Deny domain resolving\n"
" -I --conn-ip <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;
}

View File

@ -6,7 +6,12 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <arpa/inet.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#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;

View File

@ -1,5 +1,10 @@
#include <stdio.h>
#include <arpa/inet.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
enum demode {
DESYNC_NONE,

102
proxy.c
View File

@ -10,15 +10,23 @@
#include <params.h>
#include <conev.h>
#include <desync.h>
#include <error.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define close(fd) closesocket(fd)
#else
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#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 *)&params.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;
}

View File

@ -1,5 +1,10 @@
#include <stdint.h>
#include <arpa/inet.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
struct sockaddr_ina {
union {

View File

@ -5,13 +5,9 @@ $ ./ciadpi --method disorder --split-pos 3 --port 1080
Чуть более подробный текст "--help":
-i, --ip <ip>
Прослушиваемый IP, по умолчанию 0.0.0.0
Прослушиваемый IP, по умолчанию 0.0.0.0
-p, --port <num>
Прослушиваемый порт, по умолчанию 1080
-D, --daemon
Запуск в режиме демона
-f, --pidfile <file>
Записать PID в указанный файл
Прослушиваемый порт, по умолчанию 1080
-c, --max-conn <count>
Максимальное количество клиентских подключений, по умолчанию 512
-I --conn-ip <ip>
@ -30,8 +26,10 @@ $ ./ciadpi --method disorder --split-pos 3 --port 1080
Разбить первый запрос на два по определённому смещению
disorder:
Как split, но части отправляются в обратном порядке
! Поведение в Windows отлично: сначала отправляется вторая часть, затем целый запрос
fake:
Как disorder, только перед первым запросом отправляется поддельный такого же размера (т.е. равное значению split-pos)
! В Windows не поддерживается
-s, --split-pos <offset>
Смещение, по которому будет разбит запрос, по умолчанию 3