From 50c350c6aed5275ca52a0a5f00d37fd9f54ba3c7 Mon Sep 17 00:00:00 2001 From: ruti <> Date: Wed, 3 Apr 2024 22:51:02 +0300 Subject: [PATCH] replace --tr with --detect --- main.c | 54 ++++++++++----------- packets.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++------ packets.h | 8 ++++ params.h | 13 +++-- proxy.c | 39 ++++++++------- proxy.h | 19 -------- readme.txt | 19 ++++---- 7 files changed, 193 insertions(+), 97 deletions(-) diff --git a/main.c b/main.c index e88c5da..a2ca146 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,7 @@ #define close(fd) closesocket(fd) #endif -#define VERSION 7 +#define VERSION 8 #define MPOOL_INC 16 char oob_char[1] = "a"; @@ -75,7 +75,7 @@ const char help_text[] = { #ifdef TIMEOUT_SUPPORT " -T, --timeout Timeout waiting for response, after which trigger auto\n" #endif - " -P, --tr Auto trigger data in first response\n" + " -D, --detect Detect: redirect,cl_err,sid_inv,alert\n" " -s, --split Split packet at n\n" " +s - add SNI offset\n" " +h - add HTTP Host offset\n" @@ -119,7 +119,7 @@ const struct option options[] = { #ifdef TIMEOUT_SUPPORT {"timeout", 1, 0, 'T'}, #endif - {"tr", 1, 0, 'P'}, + {"detect", 1, 0, 'D'}, {"split", 1, 0, 's'}, {"disorder", 1, 0, 'd'}, {"oob", 1, 0, 'o'}, @@ -317,17 +317,6 @@ void clear_params(void) free(s.parts); s.parts = 0; } - if (s.spos) { - for (int x = 0; x < s.spos_n; x++) { - struct spos p = s.spos[x]; - if (p.data != 0) { - free(p.data); - p.data = 0;; - } - } - free(s.spos); - s.spos = 0; - } } free(params.dp); params.dp = 0; @@ -494,23 +483,28 @@ int main(int argc, char **argv) params.timeout = val; break; - case 'P':; - struct spos *spos = add((void *)&dp->spos, - &dp->spos_n, sizeof(struct spos)); - if (!spos) { - clear_params(); - 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"); - invalid = 1; + case 'D':; + end = optarg; + while (end && !invalid) { + switch (*end) { + case 'r': + dp->detect |= DETECT_HTTP_LOCAT; + break; + case 'c': + dp->detect |= DETECT_HTTP_CLERR; + break; + case 's': + dp->detect |= DETECT_TLS_INVSID; + break; + case 'a': + dp->detect |= DETECT_TLS_ALERT; + break; + default: + invalid = 1; + continue; } + end = strchr(end, ','); + if (end) end++; } break; diff --git a/packets.c b/packets.c index df2ff47..02eb906 100644 --- a/packets.c +++ b/packets.c @@ -53,6 +53,24 @@ char http_data[43] = { }; +char *strncasestr(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 (!strncasecmp(p, b, bs)) { + return p; + } + } + return 0; +} + + int find_tls_ext_offset(uint16_t type, char *data, size_t size) { if (size < 44) { @@ -145,26 +163,18 @@ int parse_tls(char *buffer, size_t bsize, char **hs) int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port) { char *host = buffer, *h_end; - size_t osz = bsize; + char *buff_end = buffer + bsize; if (bsize < 16 || *buffer > 'T' || *buffer < 'C') { return 0; } - while (1) { - host = memchr(host, '\n', osz); - if (!host) - return 0; - host++; - osz = bsize - (host - buffer); - if (osz < 6) - return 0; - if (!strncasecmp(host, "Host:", 5)) - break; - } - host += 5; osz -= 5; - for (; osz && isblank(*host); host++, osz--) {} + host = strncasestr(buffer, bsize, "\nHost:", 6); + host += 6; - char *l_end = memchr(host, '\n', osz); + while ((buff_end - host) > 0 && isblank(*host)) { + host++; + } + char *l_end = memchr(host, '\n', buff_end - host); if (!l_end) { return 0; } @@ -200,6 +210,104 @@ int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port) } +int get_http_code(char *b, ssize_t n) +{ + if (n < 13) return 0; + if (strncmp(b, "HTTP/1.", 7)) { + return 0; + } + if (!memchr(b + 13, '\n', n)) { + return 0; + } + char *e; + long num = strtol(b + 9, &e, 10); + if (num < 100 || num > 511 || !isspace(*e)) { + return 0; + } + return (int )num; +} + + +int is_http_redirect(char *req, ssize_t qn, char *resp, ssize_t sn) +{ + char *host = 0; + int len = parse_http(req, qn, &host, 0); + + if (len <= 0 || sn < 29) { + return 0; + } + int code = get_http_code(resp, sn); + if (code > 308 || code < 300) { + return 0; + } + char *location = strncasestr(resp, sn, "\nLocation:", 10); + if (!location) { + return 0; + } + location += 11; + + if ((location + 8) >= (resp + sn)) { + return 0; + } + char *l_end = memchr(location, '\n', sn - (location - resp)); + if (!l_end) { + return 0; + } + for (; isspace(*(l_end - 1)); l_end--) {} + + if ((l_end - location) > 7) { + if (!strncmp(location, "http://", 7)) { + location += 7; + } + else if (!strncmp(location, "https://", 8)) { + location += 8; + } + } + char *e = memchr(location, '/', l_end - location); + if (!e) e = l_end; + + for (; (e - location) > len; location++) { + location = memchr(location, '.', e - location); + if (!location) { + return 1; + } + } + for (; len > (e - location); host++) { + char *p = memchr(host, '.', len); + if (!p) { + return 1; + } + len -= (host - p) + 1; + host = p; + } + return (((e - location) != len) + || strncmp(host, location, len)); +} + + +int neq_tls_sid(char *req, ssize_t qn, char *resp, ssize_t sn) +{ + if (qn < 75 || sn < 75) { + return 0; + } + if (ANTOHS(req, 0) != 0x1603 + || ANTOHS(resp, 0) != 0x1603) { + return 0; + } + if (req[43] != resp[43]) { + return 1; + } + uint8_t sid_len = req[43]; + return memcmp(req + 44, resp + 44, sid_len); +} + + +int is_tls_alert(char *resp, ssize_t sn) { + return (sn >= 7 + && !memcmp(resp, "\x15\x03\x01\x00\x02\x02", 6)); +} + + int mod_http(char *buffer, size_t bsize, int m) { char *host = 0, *par; diff --git a/packets.h b/packets.h index a074768..c85677b 100644 --- a/packets.h +++ b/packets.h @@ -21,4 +21,12 @@ int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port); int mod_http(char *buffer, size_t bsize, int m); +int get_http_code(char *b, ssize_t n); + +int is_http_redirect(char *req, ssize_t qn, char *resp, ssize_t sn); + +int neq_tls_sid(char *req, ssize_t qn, char *resp, ssize_t sn); + +int is_tls_alert(char *resp, ssize_t sn); + int part_tls(char *buffer, size_t bsize, ssize_t n, int pos); diff --git a/params.h b/params.h index f3855c9..ceff35d 100644 --- a/params.h +++ b/params.h @@ -15,6 +15,11 @@ #define OFFSET_SNI 1 #define OFFSET_HOST 2 +#define DETECT_HTTP_LOCAT 1 +#define DETECT_HTTP_CLERR 2 +#define DETECT_TLS_INVSID 4 +#define DETECT_TLS_ALERT 8 + enum demode { DESYNC_NONE, DESYNC_SPLIT, @@ -49,8 +54,7 @@ struct desync_params { int mod_http; int tlsrec_n; struct part *tlsrec; - int spos_n; - struct spos *spos; + int detect; }; struct params { @@ -84,9 +88,4 @@ extern struct packet fake_tls; extern struct packet fake_http; extern struct packet oob_data; -struct spos { - ssize_t start, end, size; - char *data; -}; - extern char ip_option[1]; \ No newline at end of file diff --git a/proxy.c b/proxy.c index 575271c..8b915ce 100644 --- a/proxy.c +++ b/proxy.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #ifdef _WIN32 @@ -600,7 +601,7 @@ int try_again(struct poolhd *pool, struct eval *val, char data) if (!data) for (; m < params.dp_count; m++) { struct desync_params dp = params.dp[m]; - if (!dp.spos_n) break; + if (dp.detect == 0) break; } if (m >= params.dp_count) { mode_add_get( @@ -621,23 +622,27 @@ int try_again(struct poolhd *pool, struct eval *val, char data) } -int find_bad_data(char *buffer, ssize_t n, int m) +int find_bad_data(char *req, ssize_t qn, + char *resp, ssize_t sn, int m) { for (; m < params.dp_count; m++) { struct desync_params dp = params.dp[m]; - for (int i = 0; i < dp.spos_n; i++) { - struct spos bad_data = dp.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) { + if ((dp.detect & DETECT_HTTP_LOCAT) + && is_http_redirect(req, qn, resp, sn)) { + return m; + } + if ((dp.detect & DETECT_TLS_INVSID) + && neq_tls_sid(req, qn, resp, sn)) { + return m; + } + if ((dp.detect & DETECT_TLS_ALERT) + && is_tls_alert(resp, sn)) { + return m; + } + if (dp.detect & DETECT_HTTP_CLERR) { + int code = get_http_code(resp, sn); + if (code > 400 && code < 451 && code != 429) { return m; } } @@ -664,12 +669,14 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val, return try_again(pool, val, 0); } // - int d = find_bad_data(buffer, n, val->pair->attempt + 1); + struct eval *pair = val->pair; + + int d = find_bad_data(pair->buff.data, pair->buff.size, + buffer, n, pair->attempt + 1); if (d) { val->pair->attempt = d - 1; return try_again(pool, val, 1); } - struct eval *pair = val->pair; ssize_t sn = send(pair->fd, buffer, n, 0); if (n != sn) { diff --git a/proxy.h b/proxy.h index 3a899cd..827884e 100644 --- a/proxy.h +++ b/proxy.h @@ -94,25 +94,6 @@ 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 a9fddcd..7724e81 100644 --- a/readme.txt +++ b/readme.txt @@ -47,7 +47,7 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s Можно указывать несколько групп параметров, раделяя их данным флагом Если соединение успешно прошло, то параметры для данного IP будут закешированны Параметры, которые можно вынести в отдельную группу: - tr, split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec + detect, split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec -u, --cache-ttl Время жизни значения в кеше, по умолчанию 100800 (28 часов) @@ -57,9 +57,14 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s В Linux переводится в миллисекунды, поэтому можно указать дробное число Истечение таймаута будет обработано --auto --P, --tr - Поиск строки в первом ответе от сервера, начиная с s и заканчивая e - Является триггером для --auto в указнной группе +-D, --detect + Обнаружить некорректный ответ от сервера: + redirect: HTTP Redirect с Location, домен которого не совпадает и исходящим + cl_err : HTTP ответ, код которого равен 40x, но не 429 + sid_inv : session_id в TLS ServerHello и ClientHello не совпадают + alert : TLS Error Alert в ответе + Является триггером для --auto в указанной группе, пример: + --auto --detect redirect --split 1+h --auto --split 2+s -s, --split Разбить запрос по указанному смещению @@ -118,12 +123,6 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s -r, --tlsrec Разделить ClientHello на отдельные записи по указанному смещению Можно указывать несколько раз - --m, --mss - Установить опцию MSS для TCP соединения - Можно использовать для того, чтобы вынудить сервер разбить свой ответ - При низких значениях сильно сказывается на скорости - Поддерживается только в Linux ------- Сборка: