replace --tr with --detect

This commit is contained in:
ruti 2024-04-03 22:51:02 +03:00
parent 6f82bb1eff
commit 50c350c6ae
7 changed files with 193 additions and 97 deletions

54
main.c
View File

@ -22,7 +22,7 @@
#define close(fd) closesocket(fd) #define close(fd) closesocket(fd)
#endif #endif
#define VERSION 7 #define VERSION 8
#define MPOOL_INC 16 #define MPOOL_INC 16
char oob_char[1] = "a"; char oob_char[1] = "a";
@ -75,7 +75,7 @@ const char help_text[] = {
#ifdef TIMEOUT_SUPPORT #ifdef TIMEOUT_SUPPORT
" -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n" " -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n"
#endif #endif
" -P, --tr <s:e:f|:str> Auto trigger data in first response\n" " -D, --detect <r,c,s,a> Detect: redirect,cl_err,sid_inv,alert\n"
" -s, --split <n[+s]> Split packet at n\n" " -s, --split <n[+s]> Split packet at n\n"
" +s - add SNI offset\n" " +s - add SNI offset\n"
" +h - add HTTP Host offset\n" " +h - add HTTP Host offset\n"
@ -119,7 +119,7 @@ const struct option options[] = {
#ifdef TIMEOUT_SUPPORT #ifdef TIMEOUT_SUPPORT
{"timeout", 1, 0, 'T'}, {"timeout", 1, 0, 'T'},
#endif #endif
{"tr", 1, 0, 'P'}, {"detect", 1, 0, 'D'},
{"split", 1, 0, 's'}, {"split", 1, 0, 's'},
{"disorder", 1, 0, 'd'}, {"disorder", 1, 0, 'd'},
{"oob", 1, 0, 'o'}, {"oob", 1, 0, 'o'},
@ -317,17 +317,6 @@ void clear_params(void)
free(s.parts); free(s.parts);
s.parts = 0; 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); free(params.dp);
params.dp = 0; params.dp = 0;
@ -494,23 +483,28 @@ int main(int argc, char **argv)
params.timeout = val; params.timeout = val;
break; break;
case 'P':; case 'D':;
struct spos *spos = add((void *)&dp->spos, end = optarg;
&dp->spos_n, sizeof(struct spos)); while (end && !invalid) {
if (!spos) { switch (*end) {
clear_params(); case 'r':
return -1; dp->detect |= DETECT_HTTP_LOCAT;
} break;
sscanf(optarg, "%zi:%zi:%zn", &spos->start, &spos->end, &val); case 'c':
if (val == 0 || !optarg[val]) { dp->detect |= DETECT_HTTP_CLERR;
invalid = 1; break;
} case 's':
else { dp->detect |= DETECT_TLS_INVSID;
spos->data = ftob(&optarg[val], &spos->size); break;
if (!spos->data) { case 'a':
uniperror("read/parse"); dp->detect |= DETECT_TLS_ALERT;
invalid = 1; break;
default:
invalid = 1;
continue;
} }
end = strchr(end, ',');
if (end) end++;
} }
break; break;

138
packets.c
View File

@ -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) int find_tls_ext_offset(uint16_t type, char *data, size_t size)
{ {
if (size < 44) { 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) int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port)
{ {
char *host = buffer, *h_end; char *host = buffer, *h_end;
size_t osz = bsize; char *buff_end = buffer + bsize;
if (bsize < 16 || *buffer > 'T' || *buffer < 'C') { if (bsize < 16 || *buffer > 'T' || *buffer < 'C') {
return 0; return 0;
} }
while (1) { host = strncasestr(buffer, bsize, "\nHost:", 6);
host = memchr(host, '\n', osz); host += 6;
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--) {}
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) { if (!l_end) {
return 0; 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) int mod_http(char *buffer, size_t bsize, int m)
{ {
char *host = 0, *par; char *host = 0, *par;

View File

@ -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 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); int part_tls(char *buffer, size_t bsize, ssize_t n, int pos);

View File

@ -15,6 +15,11 @@
#define OFFSET_SNI 1 #define OFFSET_SNI 1
#define OFFSET_HOST 2 #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 { enum demode {
DESYNC_NONE, DESYNC_NONE,
DESYNC_SPLIT, DESYNC_SPLIT,
@ -49,8 +54,7 @@ struct desync_params {
int mod_http; int mod_http;
int tlsrec_n; int tlsrec_n;
struct part *tlsrec; struct part *tlsrec;
int spos_n; int detect;
struct spos *spos;
}; };
struct params { struct params {
@ -84,9 +88,4 @@ extern struct packet fake_tls;
extern struct packet fake_http; extern struct packet fake_http;
extern struct packet oob_data; extern struct packet oob_data;
struct spos {
ssize_t start, end, size;
char *data;
};
extern char ip_option[1]; extern char ip_option[1];

39
proxy.c
View File

@ -11,6 +11,7 @@
#include <params.h> #include <params.h>
#include <conev.h> #include <conev.h>
#include <desync.h> #include <desync.h>
#include <packets.h>
#include <error.h> #include <error.h>
#ifdef _WIN32 #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++) { if (!data) for (; m < params.dp_count; m++) {
struct desync_params dp = params.dp[m]; struct desync_params dp = params.dp[m];
if (!dp.spos_n) break; if (dp.detect == 0) break;
} }
if (m >= params.dp_count) { if (m >= params.dp_count) {
mode_add_get( 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++) { for (; m < params.dp_count; m++) {
struct desync_params dp = params.dp[m]; struct desync_params dp = params.dp[m];
for (int i = 0; i < dp.spos_n; i++) { if ((dp.detect & DETECT_HTTP_LOCAT)
struct spos bad_data = dp.spos[i]; && is_http_redirect(req, qn, resp, sn)) {
if (bad_data.start >= n) { return m;
continue; }
} if ((dp.detect & DETECT_TLS_INVSID)
ssize_t end = n; && neq_tls_sid(req, qn, resp, sn)) {
if (bad_data.end && bad_data.end < n) { return m;
end = bad_data.end; }
} if ((dp.detect & DETECT_TLS_ALERT)
char *found = memmem(buffer + bad_data.start, && is_tls_alert(resp, sn)) {
end - bad_data.start, bad_data.data, bad_data.size); return m;
if (found) { }
if (dp.detect & DETECT_HTTP_CLERR) {
int code = get_http_code(resp, sn);
if (code > 400 && code < 451 && code != 429) {
return m; return m;
} }
} }
@ -664,12 +669,14 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
return try_again(pool, val, 0); 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) { if (d) {
val->pair->attempt = d - 1; val->pair->attempt = d - 1;
return try_again(pool, val, 1); return try_again(pool, val, 1);
} }
struct eval *pair = val->pair;
ssize_t sn = send(pair->fd, buffer, n, 0); ssize_t sn = send(pair->fd, buffer, n, 0);
if (n != sn) { if (n != sn) {

19
proxy.h
View File

@ -94,25 +94,6 @@ enum s4_rep {
#define S_SIZE_I6 22 #define S_SIZE_I6 22
#define S_SIZE_ID 7 #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 listen_socket(struct sockaddr_ina *srv);
int event_loop(int srvfd); int event_loop(int srvfd);
int run(struct sockaddr_ina *srv); int run(struct sockaddr_ina *srv);

View File

@ -47,7 +47,7 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
Можно указывать несколько групп параметров, раделяя их данным флагом Можно указывать несколько групп параметров, раделяя их данным флагом
Если соединение успешно прошло, то параметры для данного IP будут закешированны Если соединение успешно прошло, то параметры для данного 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 <sec> -u, --cache-ttl <sec>
Время жизни значения в кеше, по умолчанию 100800 (28 часов) Время жизни значения в кеше, по умолчанию 100800 (28 часов)
@ -57,9 +57,14 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
В Linux переводится в миллисекунды, поэтому можно указать дробное число В Linux переводится в миллисекунды, поэтому можно указать дробное число
Истечение таймаута будет обработано --auto Истечение таймаута будет обработано --auto
-P, --tr <s:e:file|:str> -D, --detect <r,c,s,a>
Поиск строки в первом ответе от сервера, начиная с s и заканчивая e Обнаружить некорректный ответ от сервера:
Является триггером для --auto в указнной группе 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 <n[+s]> -s, --split <n[+s]>
Разбить запрос по указанному смещению Разбить запрос по указанному смещению
@ -118,12 +123,6 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
-r, --tlsrec <n[+s]> -r, --tlsrec <n[+s]>
Разделить ClientHello на отдельные записи по указанному смещению Разделить ClientHello на отдельные записи по указанному смещению
Можно указывать несколько раз Можно указывать несколько раз
-m, --mss <size>
Установить опцию MSS для TCP соединения
Можно использовать для того, чтобы вынудить сервер разбить свой ответ
При низких значениях сильно сказывается на скорости
Поддерживается только в Linux
------- -------
Сборка: Сборка: