This commit is contained in:
ruti 2024-03-17 00:19:14 +03:00
parent 0c6f95070c
commit 6b39efdd7a
5 changed files with 201 additions and 85 deletions

126
main.c
View File

@ -75,8 +75,9 @@ const char help_text[] = {
" -A, --auto Try desync params after this option\n"
" -u, --cache-ttl <sec> Lifetime of cached desync params for IP\n"
#ifdef TIMEOUT_SUPPORT
" -T, --timeout <sec> Timeout waiting for response\n"
" -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n"
#endif
" -P, --tr <s:e:f|:str> Auto trigger data in first response\n"
" -s, --split <n[+s]> 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 <n[+s]> Split and send fake packet\n"
" -t, --ttl <num> TTL of fake packets, default 8\n"
" -l, --fake-tls <file>\n"
" -j, --fake-http <file> Set custom fake packet\n"
" -l, --fake-tls <f|:str>\n"
" -j, --fake-http <f|:str> Set custom fake packet\n"
" -n, --tls-sni <str> Change SNI in fake ClientHello\n"
#endif
" -e, --oob-data <file> Set custom OOB data\n"
" -e, --oob-data <f|:str> Set custom OOB data, filename or :string\n"
" -M, --mod-http <h,d,r> Modify HTTP: hcsmix,dcsmix,rmspace\n"
" -r, --tlsrec <n[+s]> Make TLS record at offset\n"
" -r, --tlsrec <n[+s]> 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(
&params.dp, &params.dp_count);
struct desync_params *dp = add((void *)&params.dp,
&params.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(&params.dp, &params.dp_count);
dp = add((void *)&params.dp, &params.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 *)&params.spos,
&params.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;
}

View File

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

117
proxy.c
View File

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

19
proxy.h
View File

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

View File

@ -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 <sec>
Время жизни значения в кеше, по умолчанию 100800 (28 часов)
@ -48,10 +50,15 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
-T, --timeout <sec>
Таймаут ожидания первого ответа от сервера в секундах
В Linux переводится в миллисекунды, поэтому можно указать дробное число
Истечение таймаута будет обработано --auto
-P, --tr <s:e:file|:str>
Поиск строки в первом ответе от сервера, начиная с s и заканчивая e
Является триггером для --auto
-s, --split <n[+s]>
Разбить запрос по указанному смещению
После числа можно добавить флаг:
После числа можно добавить флаг:
+s: добавить смещение SNI
+h: добавить смещение Host
Можно указывать несколько раз, чтобы разбить запрос по нескольким позициям
@ -72,11 +79,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
TTL для поддельного пакета, по умолчанию 8
Необходимо подобрать такое значение, чтобы пакет не дошел до сервера, но был обработан DPI
-l, --fake-tls <file>
-j, --fake-http <file>
-l, --fake-tls <file|:str>
-j, --fake-http <file|:str>
Указать свои поддельные пакеты, вместо дефолтных
-e, --oob-data <file>
-e, --oob-data <file|:str>
Данные, отсылаемые вне основного потока, по умолчанию один байт 'a'
! При размере более одного байта может работать нестабильно