From 19171cfeca91d0d34e0d11daaa6a43cb4c5c2a37 Mon Sep 17 00:00:00 2001 From: ruti <> Date: Fri, 8 Mar 2024 03:37:02 +0300 Subject: [PATCH] Auto mode --- Makefile | 2 +- conev.c | 18 ++--- conev.h | 18 +++-- desync.c | 24 +++--- desync.h | 2 +- main.c | 58 ++++++++++---- mpool.c | 89 ++++++++++++++++++++++ mpool.h | 14 ++++ params.h | 17 +++-- proxy.c | 218 ++++++++++++++++++++++++++++++++++++++++------------- readme.txt | 9 ++- 11 files changed, 367 insertions(+), 102 deletions(-) create mode 100644 mpool.c create mode 100644 mpool.h diff --git a/Makefile b/Makefile index 1ee054e..28f0f9d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ 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 mpool.c all: $(CC) $(CFLAGS) $(SOURCES) -I . -o $(TARGET) diff --git a/conev.c b/conev.c index 220eeb0..3752bd6 100644 --- a/conev.c +++ b/conev.c @@ -43,15 +43,11 @@ struct eval *add_event(struct poolhd *pool, enum eid type, if (pool->count >= pool->max) return 0; struct eval *val = pool->links[pool->count]; + memset(val, 0, sizeof(*val)); val->fd = fd; val->index = pool->count; val->type = type; - val->pair = 0; - val->tmpbuf = 0; - val->size = 0; - val->offset = 0; - val->flag = 0; #ifndef NOEPOLL struct epoll_event ev = { @@ -79,9 +75,9 @@ void del_event(struct poolhd *pool, struct eval *val) if (!val->fd) { return; } - if (val->tmpbuf) { - free(val->tmpbuf); - val->tmpbuf = 0; + if (val->buff.data) { + free(val->buff.data); + val->buff.data = 0; } close(val->fd); val->fd = 0; @@ -116,9 +112,9 @@ void destroy_pool(struct poolhd *pool) close(val->fd); val->fd = 0; } - if (val->tmpbuf) { - free(val->tmpbuf); - val->tmpbuf = 0; + if (val->buff.data) { + free(val->buff.data); + val->buff.data = 0; } } if (pool->items) { diff --git a/conev.h b/conev.h index 15be03f..e01c46f 100644 --- a/conev.h +++ b/conev.h @@ -33,7 +33,8 @@ enum eid { EV_REQUEST, EV_CONNECT, EV_IGNORE, - EV_TUNNEL + EV_TUNNEL, + EV_DESYNC }; #define FLAG_S4 1 @@ -46,23 +47,30 @@ char *eid_name[] = { "EV_REQUEST", "EV_CONNECT", "EV_IGNORE", - "EV_TUNNEL" + "EV_TUNNEL", + "EV_DESYNC" }; #endif +struct buffer { + ssize_t size; + int offset; + char *data; +}; + struct eval { int fd; int index; enum eid type; struct eval *pair; - char *tmpbuf; - ssize_t size; - int offset; + struct buffer buff; int flag; union { struct sockaddr_in in; struct sockaddr_in6 in6; }; + ssize_t recv_count; + int try_count; #ifndef NOEPOLL uint32_t events; #endif diff --git a/desync.c b/desync.c index a3a515b..e56ab8c 100644 --- a/desync.c +++ b/desync.c @@ -81,7 +81,7 @@ static inline void delay(long ms) #ifndef _WIN32 int send_fake(int sfd, char *buffer, - int cnt, long pos, int fa) + int cnt, long pos, int fa, int ttl) { struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http; size_t psz = pkt.size; @@ -107,7 +107,7 @@ int send_fake(int sfd, char *buffer, } memcpy(p, pkt.data, psz < pos ? psz : pos); - if (setttl(sfd, params.ttl, fa) < 0) { + if (setttl(sfd, ttl, fa) < 0) { break; } if (_sendfile(sfd, ffd, 0, pos) < 0) { @@ -178,8 +178,10 @@ int send_disorder(int sfd, int desync(int sfd, char *buffer, size_t bfsize, - ssize_t n, struct sockaddr *dst) + ssize_t n, struct sockaddr *dst, int dp_c) { + struct desync_params dp = params.dp[dp_c]; + char *host = 0; int len = 0, type = 0; int fa = get_family(dst); @@ -195,17 +197,17 @@ int desync(int sfd, char *buffer, size_t bfsize, len, host, host - buffer); } - if (type == IS_HTTP && params.mod_http) { + if (type == IS_HTTP && dp.mod_http) { LOG(LOG_S, "modify HTTP: n=%ld\n", n); - if (mod_http(buffer, n, params.mod_http)) { + if (mod_http(buffer, n, dp.mod_http)) { LOG(LOG_E, "mod http error\n"); return -1; } } - else if (type == IS_HTTPS && params.tlsrec_n) { + else if (type == IS_HTTPS && dp.tlsrec_n) { long lp = 0; - for (int i = 0; i < params.tlsrec_n; i++) { - struct part part = params.tlsrec[i]; + for (int i = 0; i < dp.tlsrec_n; i++) { + struct part part = dp.tlsrec[i]; long pos = part.pos + i * 5; if (part.flag == OFFSET_SNI) { @@ -238,8 +240,8 @@ int desync(int sfd, char *buffer, size_t bfsize, if (!type && params.de_known) { } - else for (int i = 0; i < params.parts_n; i++) { - struct part part = params.parts[i]; + else for (int i = 0; i < dp.parts_n; i++) { + struct part part = dp.parts[i]; long pos = part.pos; if (part.flag == OFFSET_SNI) { @@ -268,7 +270,7 @@ int desync(int sfd, char *buffer, size_t bfsize, #ifndef _WIN32 case DESYNC_FAKE: s = send_fake(sfd, - buffer + lp, type, pos - lp, fa); + buffer + lp, type, pos - lp, fa, dp.ttl); break; #endif case DESYNC_DISORDER: diff --git a/desync.h b/desync.h index d934aa7..63aaa78 100644 --- a/desync.h +++ b/desync.h @@ -1 +1 @@ -int desync(int sfd, char *buffer, size_t bfsize, ssize_t n, struct sockaddr *dst); +int desync(int sfd, char *buffer, size_t bfsize, ssize_t n, struct sockaddr *dst, int dp_c); diff --git a/main.c b/main.c index 5e1d6f5..eeafc9b 100644 --- a/main.c +++ b/main.c @@ -17,13 +17,16 @@ #include #include + #ifdef __linux__ #define FAKE_SUPPORT 1 + #endif #else #include #define close(fd) closesocket(fd) #endif #define VERSION 5 +#define MPOOL_INC 16 struct packet fake_tls = { @@ -37,17 +40,10 @@ oob_data = { }; - struct params params = { - .ttl = 8, - .parts_n = 0, - .parts = 0, .sfdelay = 3, .def_ttl = 0, .custom_ttl = 0, - .mod_http = 0, - .tlsrec = 0, - .tlsrec_n = 0, .de_known = 0, .ipv6 = 1, @@ -72,6 +68,7 @@ const char help_text[] = { " -g, --def-ttl TTL for all outgoing connections\n" // desync options " -K, --desync-known Desync only HTTP and TLS with SNI\n" + " -A, --auto Try desync params after this option\n" " -s, --split Split packet at n\n" " +s - add SNI offset\n" " +h - add HTTP Host offset\n" @@ -103,6 +100,7 @@ const struct option options[] = { {"debug", 1, 0, 'x'}, {"desync-known ", 0, 0, 'K'}, + {"auto", 0, 0, 'A'}, {"split", 1, 0, 's'}, {"disorder", 1, 0, 'd'}, {"oob", 1, 0, 'o'}, @@ -229,6 +227,23 @@ int parse_offset(struct part *part, const char *str) } +struct desync_params *add_dparams( + struct desync_params **root, int *n) +{ + struct desync_params *p = realloc( + *root, sizeof(struct desync_params) * (*n + 1)); + if (!p) { + uniperror("realloc"); + return 0; + } + *root = p; + *n = *n + 1; + p = &((*root)[(*n) - 1]); + memset(p, 0, sizeof(*p)); + return p; +} + + int main(int argc, char **argv) { #ifdef _WIN32 @@ -268,6 +283,11 @@ int main(int argc, char **argv) char *end = 0; uint16_t port = htons(1080); + struct desync_params *dp = add_dparams( + ¶ms.dp, ¶ms.dp_count); + if (!dp) { + return -1; + } while (!invalid && (rez = getopt_long_only( argc, argv, opt, options, 0)) != -1) { switch (rez) { @@ -333,13 +353,20 @@ int main(int argc, char **argv) params.de_known = 1; break; + case 'A': + dp = add_dparams(¶ms.dp, ¶ms.dp_count); + if (!dp) { + return -1; + } + break; + case 's': case 'd': case 'o': case 'f': ; struct part *part = add_part( - ¶ms.parts, ¶ms.parts_n); + &dp->parts, &dp->parts_n); if (!part) { return -1; } @@ -363,7 +390,7 @@ int main(int argc, char **argv) if (val <= 0 || val > 255 || *end) invalid = 1; else - params.ttl = val; + dp->ttl = val; break; case 'n': @@ -403,13 +430,13 @@ int main(int argc, char **argv) while (end && !invalid) { switch (*end) { case 'r': - params.mod_http |= MH_SPACE; + dp->mod_http |= MH_SPACE; break; case 'h': - params.mod_http |= MH_HMIX; + dp->mod_http |= MH_HMIX; break; case 'd': - params.mod_http |= MH_DMIX; + dp->mod_http |= MH_DMIX; break; default: invalid = 1; @@ -421,7 +448,7 @@ int main(int argc, char **argv) break; case 'r': - part = add_part(¶ms.tlsrec, ¶ms.tlsrec_n); + part = add_part(&dp->tlsrec, &dp->tlsrec_n); if (!part) { return -1; } @@ -476,6 +503,11 @@ int main(int argc, char **argv) return -1; } } + params.mempool = mem_pool(MPOOL_INC); + if (!params.mempool) { + uniperror("mem_pool"); + return -1; + } int status = run(&s); #ifdef _WIN32 WSACleanup(); diff --git a/mpool.c b/mpool.c new file mode 100644 index 0000000..b9386bf --- /dev/null +++ b/mpool.c @@ -0,0 +1,89 @@ +#include +#include +#include + + +struct mphdr *mem_pool(int count) +{ + struct mphdr *hdr = malloc(sizeof(struct mphdr)); + if (!hdr) { + return 0; + } + hdr->inc = count; + hdr->max = count; + hdr->count = 0; + + hdr->values = malloc(sizeof(*hdr->values) * count); + if (!hdr->values) { + free(hdr); + hdr = 0; + } + return hdr; +} + + +int mem_index(struct mphdr *hdr, char *str, int len) +{ + if (!hdr->count) { + return -2; + } + int s = 0, m, i; + int e = hdr->count - 1; + + while (s <= e) { + m = s + (e - s) / 2; + + struct elem *val = hdr->values[m]; + if (val->len != len) + i = len < val->len ? -1 : 1; + else + i = memcmp(str, val->data, len); + + if (i > 0) + s = m + 1; + else if (i < 0) + e = m - 1; + else + return m; + } + return -(m + 2 + (i > 0 ? 1 : 0)); +} + + +struct elem *mem_add(struct mphdr *hdr, char *str, int len) +{ + int max = hdr->max; + + if (hdr->count >= max) { + max += hdr->inc; + struct elem **new = realloc(hdr->values, sizeof(*hdr->values) * max); + if (!new) { + return 0; + } + hdr->max = max; + hdr->values = new; + } + int pos = mem_index(hdr, str, len); + if (pos >= 0) { + return hdr->values[pos]; + } + pos = -pos - 2; + + struct elem *val = malloc(sizeof(struct elem) + len); + if (!val) { + return 0; + } + memset(val, 0, sizeof(*val)); + memcpy(val->data, str, len); + val->len = len; + + if (pos < hdr->count) { + void *p = &hdr->values[pos]; + void *n = &hdr->values[pos + 1]; + void *e = &hdr->values[hdr->count]; + memmove(n, p, e - p); + } + hdr->values[pos] = val; + hdr->count++; + return val; +} diff --git a/mpool.h b/mpool.h new file mode 100644 index 0000000..7293c2b --- /dev/null +++ b/mpool.h @@ -0,0 +1,14 @@ +struct elem { + int m; + int len; + char data[]; +}; +struct mphdr { + int max; + int inc; + int count; + struct elem **values; +}; +struct mphdr *mem_pool(int count); +int mem_index(struct mphdr *hdr, char *str, int len); +struct elem *mem_add(struct mphdr *hdr, char *str, int len); \ No newline at end of file diff --git a/params.h b/params.h index 1497743..70620ff 100644 --- a/params.h +++ b/params.h @@ -1,4 +1,5 @@ #include +#include #ifdef _WIN32 #include @@ -23,17 +24,22 @@ struct part { long pos; }; -struct params { - char de_known; +struct desync_params { int ttl; int parts_n; struct part *parts; - long sfdelay; - int def_ttl; - char custom_ttl; int mod_http; int tlsrec_n; struct part *tlsrec; +}; + +struct params { + char de_known; + int dp_count; + struct desync_params *dp; + long sfdelay; + int def_ttl; + char custom_ttl; char ipv6; char resolve; @@ -41,6 +47,7 @@ struct params { int debug; size_t bfsize; struct sockaddr_in6 baddr; + struct mphdr *mempool; }; extern struct params params; diff --git a/proxy.c b/proxy.c index 5067723..cfbbaac 100644 --- a/proxy.c +++ b/proxy.c @@ -434,73 +434,31 @@ static inline int on_accept(struct poolhd *pool, struct eval *val) } -static inline int on_connect(struct poolhd *pool, struct eval *val, - char *buffer, size_t bfsize, int e) -{ - if (val->flag == FLAG_CONN) { - int error = 0; - socklen_t len = sizeof(error); - if (e) { - if (getsockopt(val->fd, SOL_SOCKET, - SO_ERROR, (char *)&error, &len)) { - uniperror("getsockopt SO_ERROR"); - return -1; - } - } - if (resp_error(val->pair->fd, - error, val->pair->flag) < 0) { - uniperror("send"); - return -1; - } - if (e) { - return -1; - } - if (mod_etype(pool, val, POLLOUT, 0)) { - uniperror("mod_etype"); - return -1; - } - val->type = EV_TUNNEL; - val->pair->type = EV_CONNECT; - } - else { - ssize_t n = recv(val->fd, buffer, bfsize, 0); - if (n <= 0) { - if (n) uniperror("recv data"); - return -1; - } - if (desync(val->pair->fd, buffer, bfsize, - n, (struct sockaddr *)&val->pair->in6)) { - return -1; - } - val->type = EV_TUNNEL; - } - return 0; -} - - static inline int on_tunnel(struct poolhd *pool, struct eval *val, char *buffer, size_t bfsize, int out) { ssize_t n = 0; struct eval *pair = val->pair; - if (pair->tmpbuf && out) { + if (pair->buff.size && out) { pair = val; val = val->pair; - n = val->size - val->offset; - ssize_t sn = send(pair->fd, val->tmpbuf + val->offset, n, 0); + n = val->buff.size - val->buff.offset; + ssize_t sn = send(pair->fd, + val->buff.data + val->buff.offset, n, 0); if (sn != n) { if (sn < 0 && get_e() != EAGAIN) { uniperror("send"); return -1; } if (sn > 0) - val->offset += sn; + val->buff.offset += sn; return 0; } - free(val->tmpbuf); - val->tmpbuf = 0; + free(val->buff.data); + val->buff.data = 0; + val->buff.size = 0; if (mod_etype(pool, val, POLLIN, 1) || mod_etype(pool, pair, POLLOUT, 0)) { @@ -516,6 +474,8 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, if (n) uniperror("recv"); return -1; } + val->recv_count += n; + ssize_t sn = send(pair->fd, buffer, n, 0); if (sn != n) { if (sn < 0) { @@ -527,12 +487,12 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, } LOG(LOG_S, "EAGAIN, set POLLOUT (fd: %d)\n", pair->fd); - val->size = n - sn; - if (!(val->tmpbuf = malloc(val->size))) { + val->buff.size = n - sn; + if (!(val->buff.data = malloc(val->buff.size))) { uniperror("malloc"); return -1; } - memcpy(val->tmpbuf, buffer + sn, val->size); + memcpy(val->buff.data, buffer + sn, val->buff.size); if (mod_etype(pool, val, POLLIN, 0) || mod_etype(pool, pair, POLLOUT, 1)) { @@ -546,6 +506,150 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, } +int try_again(struct poolhd *pool, struct eval *val) +{ + if (val->flag != FLAG_CONN) { + return -1; + } + if (val->recv_count) { + return -1; + } + struct eval *client = val->pair; + if (client->try_count >= params.dp_count) { + return -1; + } + LOG(LOG_S, "try next params: %d\n", client->try_count + 1); + + int e = create_conn(pool, client, + (struct sockaddr_ina *)&val->in6); + if (e) { + return -1; + } + val->pair = 0; + del_event(pool, val); + + client->type = EV_IGNORE; + client->try_count++; + return 0; +} + + +int mode_add_get(struct sockaddr_ina *dst, int m) +{ + char *data; + int len; + if (dst->sa.sa_family == AF_INET) { + data = (char *)(&dst->in.sin_addr); + len = sizeof(dst->in.sin_addr); + } else { + data = (char *)(&dst->in6.sin6_addr); + len = sizeof(dst->in6.sin6_addr); + } + struct elem *val; + if (m >= 0) { + val = mem_add(params.mempool, data, len); + if (!val) { + uniperror("mem_add"); + return -1; + } + val->m = m; + return 0; + } + int i = mem_index(params.mempool, data, len); + if (i < 0) { + return -1; + } + val = params.mempool->values[i]; + return val->m; +} + + +int on_desync(struct poolhd *pool, struct eval *val, + char *buffer, size_t bfsize) +{ + ssize_t n; + int m; + + if (val->flag == FLAG_CONN) { + if (on_tunnel(pool, val, buffer, bfsize, 0)) { + return try_again(pool, val); + } + free(val->pair->buff.data); + val->pair->buff.data = 0; + val->pair->buff.size = 0; + + m = val->pair->try_count; + return mode_add_get( + (struct sockaddr_ina *)&val->in6, m); + } + m = mode_add_get( + (struct sockaddr_ina *)&val->pair->in6, -1); + if (m < 0) { + m = val->try_count; + } + if (!val->buff.data) { + n = recv(val->fd, buffer, bfsize, 0); + if (n <= 0) { + if (n) uniperror("recv data"); + return -1; + } + val->recv_count += n; + val->buff.size = n; + + if (!(val->buff.data = malloc(n))) { + uniperror("malloc"); + return -1; + } + memcpy(val->buff.data, buffer, n); + } else { + n = val->buff.size; + memcpy(buffer, val->buff.data, n); + } + if (desync(val->pair->fd, buffer, bfsize, n, + (struct sockaddr *)&val->pair->in6, m)) { + return -1; + } + val->type = EV_TUNNEL; + return 0; +} + + +static inline int on_connect(struct poolhd *pool, struct eval *val, + char *buffer, size_t bfsize, int e) +{ + int error = 0; + socklen_t len = sizeof(error); + if (e) { + if (getsockopt(val->fd, SOL_SOCKET, + SO_ERROR, (char *)&error, &len)) { + uniperror("getsockopt SO_ERROR"); + return -1; + } + } + if (!val->pair->try_count) { + if (resp_error(val->pair->fd, + error, val->pair->flag) < 0) { + uniperror("send"); + return -1; + } + } + if (e) { + return -1; + } + if (mod_etype(pool, val, POLLOUT, 0)) { + uniperror("mod_etype"); + return -1; + } + val->type = EV_DESYNC; + val->pair->type = EV_DESYNC; + + if (val->pair->try_count) { + return on_desync(pool, val->pair, buffer, bfsize); + } + return 0; +} + + int event_loop(int srvfd) { size_t bfsize = params.bfsize; @@ -600,8 +704,9 @@ int event_loop(int srvfd) case EV_TUNNEL: if (on_tunnel(pool, val, - buffer, bfsize, etype & POLLOUT)) + buffer, bfsize, etype & POLLOUT)) { del_event(pool, val); + } continue; case EV_CONNECT: @@ -610,6 +715,11 @@ int event_loop(int srvfd) del_event(pool, val); continue; + case EV_DESYNC: + if (on_desync(pool, val, buffer, bfsize)) + del_event(pool, val); + continue; + case EV_IGNORE: if (etype & (POLLHUP | POLLERR | POLLRDHUP)) del_event(pool, val); diff --git a/readme.txt b/readme.txt index ddb0fba..09a5c49 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ -------------- Использование: -$ ./ciadpi --disorder 3+sni +$ ./ciadpi --disorder 3 -A --tlsrec 1+s Описание аргументов: -i, --ip @@ -35,6 +35,13 @@ $ ./ciadpi --disorder 3+sni Отключить запутывание для нераспознанных протоколов Распознаваемые протоколы: HTTP и TLS с SNI +-A, --auto + Автоматический режим + Если обнаружены признаки блокировки (соединение разорвано сразу после первого пакета), + то будут применены параметры обхода, следующие за данной опцией + Можно указывать несколько групп параметров, раделяя их данным флагом + Если соединение успешно прошло, то параметры будут сохранены для данного IP до следующего перезапуска + -s, --split Разбить запрос по указанному смещению После числа можно добавить флаг: