From 6b39efdd7a2e104989bef19abae7711694aa6cb0 Mon Sep 17 00:00:00 2001 From: ruti <> Date: Sun, 17 Mar 2024 00:19:14 +0300 Subject: [PATCH] Add --tr --- main.c | 126 +++++++++++++++++++++++++++++++++++++---------------- params.h | 7 +++ proxy.c | 117 +++++++++++++++++++++++++++++++------------------ proxy.h | 19 ++++++++ readme.txt | 17 +++++--- 5 files changed, 201 insertions(+), 85 deletions(-) diff --git a/main.c b/main.c index ca0f877..3681028 100644 --- a/main.c +++ b/main.c @@ -75,8 +75,9 @@ const char help_text[] = { " -A, --auto Try desync params after this option\n" " -u, --cache-ttl Lifetime of cached desync params for IP\n" #ifdef TIMEOUT_SUPPORT - " -T, --timeout Timeout waiting for response\n" + " -T, --timeout Timeout waiting for response, after which trigger auto\n" #endif + " -P, --tr Auto trigger data in first response\n" " -s, --split Split packet at n\n" " +s - add SNI offset\n" " +h - add HTTP Host offset\n" @@ -85,13 +86,13 @@ const char help_text[] = { #ifdef FAKE_SUPPORT " -f, --fake Split and send fake packet\n" " -t, --ttl TTL of fake packets, default 8\n" - " -l, --fake-tls \n" - " -j, --fake-http Set custom fake packet\n" + " -l, --fake-tls \n" + " -j, --fake-http Set custom fake packet\n" " -n, --tls-sni Change SNI in fake ClientHello\n" #endif - " -e, --oob-data Set custom OOB data\n" + " -e, --oob-data Set custom OOB data, filename or :string\n" " -M, --mod-http Modify HTTP: hcsmix,dcsmix,rmspace\n" - " -r, --tlsrec Make TLS record at offset\n" + " -r, --tlsrec Make TLS record at position\n" }; @@ -113,6 +114,7 @@ const struct option options[] = { #ifdef TIMEOUT_SUPPORT {"timeout", 1, 0, 'T'}, #endif + {"tr", 1, 0, 'P'}, {"split", 1, 0, 's'}, {"disorder", 1, 0, 'd'}, {"oob", 1, 0, 'o'}, @@ -132,12 +134,57 @@ const struct option options[] = { }; -char *ftob(char *name, ssize_t *sl) +char *parse_cform(const char *str, ssize_t *size) { + ssize_t len = strlen(str); + char *d = malloc(len); + if (!d) { + return 0; + } + static char esca[] = { + 'r','\r','n','\n','t','\t','\\','\\', + 'f','\f','b','\b','v','\v','a','\a', 0 + }; + ssize_t i = 0, p = 0; + for (; p < len; ++p && ++i) { + if (str[p] != '\\') { + d[i] = str[p]; + continue; + } + p++; + char *e = esca; + for (; *e; e += 2) { + if (*e == str[p]) { + d[i] = *(e + 1); + break; + } + } + if (*e) { + continue; + } + int n = 0; + if (sscanf(&str[p], "x%2hhx%n", &d[i], &n) == 1 + || sscanf(&str[p], "%3hho%n", &d[i], &n) == 1) { + p += (n - 1); + continue; + } + i--; p--; + } + *size = i; + char *m = realloc(d, i); + return m ? m : d; +} + + +char *ftob(const char *str, ssize_t *sl) +{ + if (*str == ':') { + return parse_cform(str + 1, sl); + } char *buffer = 0; long size; - FILE *file = fopen(name, "rb"); + FILE *file = fopen(str, "rb"); if (!file) return 0; do { @@ -164,7 +211,7 @@ char *ftob(char *name, ssize_t *sl) } -int get_addr(char *str, struct sockaddr_ina *addr) +int get_addr(const char *str, struct sockaddr_ina *addr) { struct addrinfo hints = {0}, *res = 0; @@ -203,20 +250,6 @@ int get_default_ttl() } -struct part *add_part(struct part **root, int *n) -{ - struct part *p = realloc( - *root, sizeof(struct part) * (*n + 1)); - if (!p) { - uniperror("realloc"); - return 0; - } - *root = p; - *n = *n + 1; - return &((*root)[(*n) - 1]); -} - - int parse_offset(struct part *part, const char *str) { char *end = 0; @@ -239,19 +272,17 @@ int parse_offset(struct part *part, const char *str) } -struct desync_params *add_dparams( - struct desync_params **root, int *n) +void *add(void **root, int *n, size_t ss) { - struct desync_params *p = realloc( - *root, sizeof(struct desync_params) * (*n + 1)); + void *p = realloc(*root, ss * (*n + 1)); if (!p) { uniperror("realloc"); return 0; } *root = p; + p = ((*root) + ((*n) * ss)); + memset(p, 0, ss); *n = *n + 1; - p = &((*root)[(*n) - 1]); - memset(p, 0, sizeof(*p)); return p; } @@ -296,8 +327,8 @@ int main(int argc, char **argv) uint16_t port = htons(1080); - struct desync_params *dp = add_dparams( - ¶ms.dp, ¶ms.dp_count); + struct desync_params *dp = add((void *)¶ms.dp, + ¶ms.dp_count, sizeof(struct desync_params)); if (!dp) { return -1; } @@ -367,7 +398,8 @@ int main(int argc, char **argv) break; case 'A': - dp = add_dparams(¶ms.dp, ¶ms.dp_count); + dp = add((void *)¶ms.dp, ¶ms.dp_count, + sizeof(struct desync_params)); if (!dp) { return -1; } @@ -394,13 +426,32 @@ int main(int argc, char **argv) params.timeout = val; break; + case 'P':; + struct spos *spos = add((void *)¶ms.spos, + ¶ms.spos_n, sizeof(struct spos)); + if (!spos) { + return -1; + } + sscanf(optarg, "%zi:%zi:%zn", &spos->start, &spos->end, &val); + if (val == 0 || !optarg[val]) { + invalid = 1; + } + else { + spos->data = ftob(&optarg[val], &spos->size); + if (!spos->data) { + uniperror("read/parse"); + return -1; + } + } + break; + case 's': case 'd': case 'o': case 'f': ; - struct part *part = add_part( - &dp->parts, &dp->parts_n); + struct part *part = add((void *)&dp->parts, + &dp->parts_n, sizeof(struct part)); if (!part) { return -1; } @@ -438,7 +489,7 @@ int main(int argc, char **argv) case 'l': fake_tls.data = ftob(optarg, &fake_tls.size); if (!fake_tls.data) { - uniperror("read file"); + uniperror("read/parse"); return -1; } break; @@ -446,7 +497,7 @@ int main(int argc, char **argv) case 'j': fake_http.data = ftob(optarg, &fake_http.size); if (!fake_http.data) { - uniperror("read file"); + uniperror("read/parse"); return -1; } break; @@ -454,7 +505,7 @@ int main(int argc, char **argv) case 'e': oob_data.data = ftob(optarg, &oob_data.size); if (!oob_data.data) { - uniperror("read file"); + uniperror("read/parse"); return -1; } break; @@ -482,7 +533,8 @@ int main(int argc, char **argv) break; case 'r': - part = add_part(&dp->tlsrec, &dp->tlsrec_n); + part = add((void *)&dp->tlsrec, + &dp->tlsrec_n, sizeof(struct part)); if (!part) { return -1; } diff --git a/params.h b/params.h index e624ee5..3470f39 100644 --- a/params.h +++ b/params.h @@ -43,6 +43,8 @@ struct params { unsigned int timeout; long cache_ttl; + int spos_n; + struct spos *spos; char ipv6; char resolve; int max_open; @@ -61,3 +63,8 @@ struct packet { extern struct packet fake_tls; extern struct packet fake_http; extern struct packet oob_data; + +struct spos { + ssize_t start, end, size; + char *data; +}; \ No newline at end of file diff --git a/proxy.c b/proxy.c index 52d62b3..d723d9e 100644 --- a/proxy.c +++ b/proxy.c @@ -447,7 +447,7 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, break; if (n < 1) { if (n) uniperror("recv"); - return get_e(); + return -1; } val->recv_count += n; @@ -603,51 +603,82 @@ int try_again(struct poolhd *pool, struct eval *val) } +char find_bad_data(char *buffer, ssize_t n) +{ + for (int i = 0; i < params.spos_n; i++) { + struct spos bad_data = params.spos[i]; + if (bad_data.start >= n) { + continue; + } + ssize_t end = n; + if (bad_data.end && bad_data.end < n) { + end = bad_data.end; + } + char *found = memmem(buffer + bad_data.start, + end - bad_data.start, bad_data.data, bad_data.size); + if (found) { + return 1; + } + } + return 0; +} + + int on_tunnel_check(struct poolhd *pool, struct eval *val, char *buffer, size_t bfsize, int out) { - int e = on_tunnel(pool, val, buffer, bfsize, out); - - if (val->flag == FLAG_CONN) { - if (out) { - return e; - } - if (e) { - switch (unie(e)) { - case ECONNRESET: - case ETIMEDOUT: - break; - default: return -1; - } - return try_again(pool, val); - } - struct eval *pair = val->pair; - val->type = EV_TUNNEL; - pair->type = EV_TUNNEL; - - free(pair->buff.data); - pair->buff.data = 0; - pair->buff.size = 0; - - if (params.timeout && - set_timeout(val->fd, 0)) { - return -1; - } - int m = pair->attempt; - - if ((m == 0 && val->attempt < 0) - || (m && m == val->attempt)) { - return 0; - } - if (m == 0) { - LOG(LOG_S, "delete ip: m=%d\n", m); - } else { - LOG(LOG_S, "save ip: m=%d\n", m); - } - return mode_add_get( - (struct sockaddr_ina *)&val->in6, m); + if (out) { + return on_tunnel(pool, val, buffer, bfsize, out); } - return e; + ssize_t n = recv(val->fd, buffer, bfsize, 0); + if (n < 1) { + uniperror("recv"); + switch (unie(get_e())) { + case ECONNRESET: + case ETIMEDOUT: + break; + default: return -1; + } + return try_again(pool, val); + } + // + char found_bd = find_bad_data(buffer, n); + if (found_bd && + !try_again(pool, val)) { + return 0; + } + struct eval *pair = val->pair; + + ssize_t sn = send(pair->fd, buffer, n, 0); + if (n != sn) { + uniperror("send"); + return -1; + } + val->type = EV_TUNNEL; + pair->type = EV_TUNNEL; + + free(pair->buff.data); + pair->buff.data = 0; + pair->buff.size = 0; + + if (params.timeout && + set_timeout(val->fd, 0)) { + return -1; + } + int m = pair->attempt; + + if ((m == 0 && val->attempt < 0) + || (m && m == val->attempt) + || found_bd) { + return 0; + } + if (m == 0) { + LOG(LOG_S, "delete ip: m=%d\n", m); + } else { + LOG(LOG_S, "save ip: m=%d\n", m); + } + return mode_add_get( + (struct sockaddr_ina *)&val->in6, m); } @@ -692,7 +723,7 @@ int on_desync(struct poolhd *pool, struct eval *val, (struct sockaddr *)&val->pair->in6, m)) { return -1; } - val->type = EV_PRE_TUNNEL; + val->type = EV_TUNNEL; val->pair->type = EV_PRE_TUNNEL; return 0; } diff --git a/proxy.h b/proxy.h index 827884e..3a899cd 100644 --- a/proxy.h +++ b/proxy.h @@ -94,6 +94,25 @@ enum s4_rep { #define S_SIZE_I6 22 #define S_SIZE_ID 7 +#ifndef __linux__ +inline char *memmem(char *a, ssize_t as, char *b, ssize_t bs) +{ + for (char *p = a; ; p++) { + p = memchr(p, *b, as - (p - a)); + if (!p) { + return 0; + } + if ((p + bs) > (a + as)) { + return 0; + } + if (!memcmp(p, b, bs)) { + return p; + } + } + return 0; +} +#endif + int listen_socket(struct sockaddr_ina *srv); int event_loop(int srvfd); int run(struct sockaddr_ina *srv); diff --git a/readme.txt b/readme.txt index a4dff85..7c74c79 100644 --- a/readme.txt +++ b/readme.txt @@ -37,10 +37,12 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s -A, --auto Автоматический режим - Если сервер сбросил подключение после первого запроса, + Если сервер сбросил подключение, превышено время ожидания, сработал --tr, то будут применены параметры обхода, следующие за данной опцией Можно указывать несколько групп параметров, раделяя их данным флагом Если соединение успешно прошло, то параметры для данного IP будут закешированны + Параметры, которые можно вынести в отдельную группу: + split, disorder, oob, fake, ttl, mod-http, tlsrec -u, --cache-ttl Время жизни значения в кеше, по умолчанию 100800 (28 часов) @@ -48,10 +50,15 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s -T, --timeout Таймаут ожидания первого ответа от сервера в секундах В Linux переводится в миллисекунды, поэтому можно указать дробное число + Истечение таймаута будет обработано --auto + +-P, --tr + Поиск строки в первом ответе от сервера, начиная с s и заканчивая e + Является триггером для --auto -s, --split Разбить запрос по указанному смещению - После числа можно добавить флаг: + После числа можно добавить флаг: +s: добавить смещение SNI +h: добавить смещение Host Можно указывать несколько раз, чтобы разбить запрос по нескольким позициям @@ -72,11 +79,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s TTL для поддельного пакета, по умолчанию 8 Необходимо подобрать такое значение, чтобы пакет не дошел до сервера, но был обработан DPI --l, --fake-tls --j, --fake-http +-l, --fake-tls +-j, --fake-http Указать свои поддельные пакеты, вместо дефолтных --e, --oob-data +-e, --oob-data Данные, отсылаемые вне основного потока, по умолчанию один байт 'a' ! При размере более одного байта может работать нестабильно