From 3b65b275b151ef76e42446f0298d49b7eef0fb79 Mon Sep 17 00:00:00 2001 From: ruti <> Date: Tue, 16 Apr 2024 20:55:41 +0300 Subject: [PATCH] avl, --hosts, --dst --- conev.h | 1 + main.c | 109 ++++++++++++++++++++++++++++++++++---- mpool.c | 151 +++++++++++++++++++++-------------------------------- mpool.h | 29 ++++++---- params.h | 5 ++ proxy.c | 147 ++++++++++++++++++++++++++++++++++----------------- readme.txt | 17 +++++- 7 files changed, 296 insertions(+), 163 deletions(-) diff --git a/conev.h b/conev.h index 38c1b22..176632a 100644 --- a/conev.h +++ b/conev.h @@ -73,6 +73,7 @@ struct eval { }; ssize_t recv_count; int attempt; + char cache; #ifndef NOEPOLL uint32_t events; #endif diff --git a/main.c b/main.c index 2beea7e..39e4bf2 100644 --- a/main.c +++ b/main.c @@ -17,12 +17,13 @@ #include #include #include + #include #else #include #define close(fd) closesocket(fd) #endif -#define VERSION "8.1" +#define VERSION "10" #define MPOOL_INC 16 @@ -71,12 +72,15 @@ const char help_text[] = { #ifdef TCP_FASTOPEN_CONNECT " -F, --tfo Enable TCP Fast Open\n" #endif - " -A, --auto[=t,r,c,s,a] Try desync params after this option\n" - " Detect: torst,redirect,cl_err,sid_inv,alert\n" + " -L, --late-conn Waiting for request before connecting\n" + " -A, --auto[=t,r,c,s,a,n] Try desync params after this option\n" + " Detect: torst,redirect,cl_err,sid_inv,alert,nop\n" " -u, --cache-ttl Lifetime of cached desync params for IP\n" #ifdef TIMEOUT_SUPPORT " -T, --timeout Timeout waiting for response, after which trigger auto\n" #endif + " -H, --hosts Hosts whitelist\n" + " -D, --dst Custom destination IP\n" " -s, --split Split packet at n\n" " +s - add SNI offset\n" " +h - add HTTP Host offset\n" @@ -115,11 +119,14 @@ const struct option options[] = { #ifdef TCP_FASTOPEN_CONNECT {"tfo ", 0, 0, 'F'}, #endif + {"late-conn", 0, 0, 'L'}, {"auto", 2, 0, 'A'}, {"cache-ttl", 1, 0, 'u'}, #ifdef TIMEOUT_SUPPORT {"timeout", 1, 0, 'T'}, #endif + {"hosts", 1, 0, 'H'}, + {"dst", 1, 0, 'D'}, {"split", 1, 0, 's'}, {"disorder", 1, 0, 'd'}, {"oob", 1, 0, 'o'}, @@ -195,16 +202,27 @@ char *ftob(const char *str, ssize_t *sl) long size; FILE *file = fopen(str, "rb"); - if (!file) + if (!file) { return 0; + } do { if (fseek(file, 0, SEEK_END)) { break; } size = ftell(file); - if (!size || fseek(file, 0, SEEK_SET)) { + if (size <= 0) { break; } + if (fseek(file, 0, SEEK_SET)) { + break; + } + #ifndef _WIN32 + buffer = mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file), 0); + if (buffer == MAP_FAILED) { + buffer = 0; + break; + } + #else if (!(buffer = malloc(size))) { break; } @@ -212,6 +230,7 @@ char *ftob(const char *str, ssize_t *sl) free(buffer); buffer = 0; } + #endif } while (0); if (buffer) { *sl = size; @@ -221,6 +240,33 @@ char *ftob(const char *str, ssize_t *sl) } +struct mphdr *parse_hosts(char *buffer, size_t size) +{ + struct mphdr *hdr = mem_pool(1); + if (!hdr) { + return 0; + } + char *end = buffer + size; + char *e = buffer, *s = buffer; + + for (; e <= end; e++) { + if (*e != ' ' && *e != '\n' && e != end) { + continue; + } + if (s == e) { + s++; + continue; + } + if (mem_add(hdr, s, e - s) == 0) { + free(hdr); + return 0; + } + s = e + 1; + } + return hdr; +} + + int get_addr(const char *str, struct sockaddr_ina *addr) { struct addrinfo hints = {0}, *res = 0; @@ -284,18 +330,23 @@ int parse_offset(struct part *part, const char *str) void *add(void **root, int *n, size_t ss) { - void *p = realloc(*root, ss * (*n + 1)); + char *p = realloc(*root, ss * (*n + 1)); if (!p) { uniperror("realloc"); return 0; } *root = p; - p = ((*root) + ((*n) * ss)); + p = (p + ((*n) * ss)); memset(p, 0, ss); *n = *n + 1; return p; } +#ifndef _WIN32 +#define FREE(p, s) munmap(p, s) +#else +#define FREE(p, s) free(p) +#endif void clear_params(void) { @@ -322,15 +373,15 @@ void clear_params(void) params.dp = 0; } if (fake_tls.data != tls_data) { - free(fake_tls.data); + FREE(fake_tls.data, fake_tls.size); fake_tls.data = tls_data; } if (fake_http.data != http_data) { - free(fake_http.data); + FREE(fake_http.data, fake_http.size); fake_http.data = http_data; } if (oob_data.data != oob_char) { - free(oob_data.data); + FREE(oob_data.data, oob_data.size); oob_data.data = oob_char; } } @@ -382,6 +433,7 @@ int main(int argc, char **argv) clear_params(); return -1; } + while (!invalid && (rez = getopt_long_only( argc, argv, opt, options, 0)) != -1) { switch (rez) { @@ -445,6 +497,10 @@ int main(int argc, char **argv) // desync options + case 'L': + params.late_conn = 1; + break; + case 'K': params.de_known = 1; break; @@ -482,6 +538,8 @@ int main(int argc, char **argv) case 'a': dp->detect |= DETECT_TLS_ALERT; break; + case 'n': + break; default: invalid = 1; continue; @@ -512,6 +570,27 @@ int main(int argc, char **argv) params.timeout = val; break; + case 'H':; + char *data = ftob(optarg, &val); + if (!data) { + uniperror("read/parse"); + invalid = 1; + } + dp->hosts = parse_hosts(data, val); + if (!dp->hosts) { + perror("parse_hosts"); + clear_params(); + return -1; + } + break; + + case 'D': + if (get_addr(optarg, (struct sockaddr_ina *)&dp->addr) < 0) + invalid = 1; + else + dp->to_ip = 2; + break; + case 's': case 'd': case 'o': @@ -671,6 +750,14 @@ int main(int argc, char **argv) clear_params(); return -1; } + if (dp->hosts) { + dp = add((void *)¶ms.dp, + ¶ms.dp_count, sizeof(struct desync_params)); + if (!dp) { + clear_params(); + return -1; + } + } s.in.sin_port = port; b.in.sin_port = 0; @@ -683,7 +770,7 @@ int main(int argc, char **argv) return -1; } } - params.mempool = mem_pool(MPOOL_INC); + params.mempool = mem_pool(0); if (!params.mempool) { uniperror("mem_pool"); clear_params(); diff --git a/mpool.c b/mpool.c index 4b914de..4b89f19 100644 --- a/mpool.c +++ b/mpool.c @@ -3,129 +3,98 @@ #include -struct mphdr *mem_pool(int count) +static inline int scmp(const struct elem *p, const struct elem *q) { - struct mphdr *hdr = malloc(sizeof(struct mphdr)); - if (!hdr) { - return 0; + if (p->len != q ->len) { + return p->len < q->len ? -1 : 1; } - hdr->inc = count; - hdr->max = count; - hdr->count = 0; + return memcmp(p->data, q->data, p->len); +} - hdr->values = malloc(sizeof(*hdr->values) * count); - if (!hdr->values) { - free(hdr); - hdr = 0; +KAVL_INIT(my, struct elem, head, scmp) + + +struct mphdr *mem_pool(bool cst) +{ + struct mphdr *hdr = calloc(sizeof(struct mphdr), 1); + if (hdr) { + hdr->stat = cst; } return hdr; } -int mem_index(struct mphdr *hdr, char *str, int len) +struct elem *mem_get(struct mphdr *hdr, char *str, int len) { - if (!hdr->count) { - return -2; - } - int s = 0, m, i; - int e = hdr->count - 1; + struct { + int len; + char *data; + } temp = { .len = len, .data = str }; - 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)); + return kavl_find(my, hdr->root, (struct elem *)&temp, 0); } -struct elem *mem_add(struct mphdr *hdr, char *str, int len, int pos) +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; - } - if (pos >= 0) { - return hdr->values[pos]; - } - pos = -pos - 2; - - struct elem *val = malloc(sizeof(struct elem) + len); - if (!val) { + struct elem *v, *e = malloc(sizeof(struct elem)); + if (!e) { 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); + e->len = len; + if (!hdr->stat) { + e->data = malloc(len); + if (!e->data) { + free(e); + return 0; + } + memcpy(e->data, str, len); } - hdr->values[pos] = val; - hdr->count++; - return val; + else { + e->data = str; + } + v = kavl_insert(my, &hdr->root, e, 0); + if (e != v) { + if (!hdr->stat) { + free(e->data); + } + free(e); + } + return v; } -void mem_delete(struct mphdr *hdr, int pos) +void mem_delete(struct mphdr *hdr, char *str, int len) { - int max = hdr->max; - if (!hdr->count) { + struct { + int len; + char *data; + } temp = { .len = len, .data = str }; + + struct elem *e = kavl_erase(my, &hdr->root, (struct elem *)&temp, 0); + if (!e) { return; } - if (max > hdr->inc && - (max - hdr->count) > hdr->inc * 2) { - max -= hdr->inc; - struct elem **new = realloc(hdr->values, sizeof(*hdr->values) * max); - if (new) { - hdr->max = max; - hdr->values = new; - } + if (!hdr->stat) { + free(e->data); + e->data = 0; } - free(hdr->values[pos]); - - if (pos < hdr->count) { - void *p = &hdr->values[pos]; - void *n = &hdr->values[pos + 1]; - void *e = &hdr->values[hdr->count]; - memmove(p, n, e - n); - } - hdr->count--; + free(e); } void mem_destroy(struct mphdr *hdr) { - for (int i = 0; i < hdr->count && hdr->values; i++) { - struct elem *e = hdr->values[i]; + while (hdr->root) { + struct elem *e = kavl_erase_first(my, &hdr->root); if (!e) { - continue; + break; } + if (!hdr->stat && e->data) { + free(e->data); + } + e->data = 0; free(e); - hdr->values[i] = 0; } - free(hdr->values); - memset(hdr, 0, sizeof(*hdr)); free(hdr); } \ No newline at end of file diff --git a/mpool.h b/mpool.h index f1a8f00..8f5d47d 100644 --- a/mpool.h +++ b/mpool.h @@ -1,19 +1,26 @@ +#include #include +#include "kavl.h" struct elem { + int len; + char *data; int m; time_t time; - int len; - char data[]; + KAVL_HEAD(struct elem) head; }; + struct mphdr { - int max; - int inc; - int count; - struct elem **values; + bool stat; + struct elem *root; }; -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, int pos); -void mem_delete(struct mphdr *hdr, int pos); -void mem_destroy(struct mphdr *hdr); \ No newline at end of file + +struct mphdr *mem_pool(bool cst); + +struct elem *mem_get(struct mphdr *hdr, char *str, int len); + +struct elem *mem_add(struct mphdr *hdr, char *str, int len); + +void mem_delete(struct mphdr *hdr, char *str, int len); + +void mem_destroy(struct mphdr *hdr); diff --git a/params.h b/params.h index aadf630..1c72541 100644 --- a/params.h +++ b/params.h @@ -56,6 +56,10 @@ struct desync_params { int tlsrec_n; struct part *tlsrec; int detect; + struct mphdr *hosts; + + char to_ip; + struct sockaddr_in6 addr; }; struct params { @@ -67,6 +71,7 @@ struct params { int def_ttl; char custom_ttl; + char late_conn; char tfo; unsigned int timeout; long cache_ttl; diff --git a/proxy.c b/proxy.c index 48634cf..d4936a7 100644 --- a/proxy.c +++ b/proxy.c @@ -497,34 +497,26 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, int mode_add_get(struct sockaddr_ina *dst, int m) { // m < 0: get, m > 0: set, m == 0: delete - int len; time_t t; struct elem *val; - - struct { - uint16_t port; - union { - struct in_addr ip4; - struct in6_addr ip6; - }; - } str = { .port = dst->in.sin_port }; + char *str = (char *)&dst->in; + int len = sizeof(dst->sa.sa_family); if (dst->sa.sa_family == AF_INET) { - str.ip4 = dst->in.sin_addr; - len = sizeof(str.port) + sizeof(str.ip4); + len = sizeof(dst->in); } else { - str.ip6 = dst->in6.sin6_addr; - len = sizeof(str); + len = sizeof(dst->in6) - sizeof(dst->in6.sin6_scope_id); } - int i = mem_index(params.mempool, (char *)&str, len); - if (m == 0 && i >= 0) { - mem_delete(params.mempool, i); + len -= sizeof(dst->sa.sa_family); + + if (m == 0) { + mem_delete(params.mempool, str, len); return 0; } else if (m > 0) { time(&t); - val = mem_add(params.mempool, (char *)&str, len, i); + val = mem_add(params.mempool, str, len); if (!val) { uniperror("mem_add"); return -1; @@ -533,10 +525,10 @@ int mode_add_get(struct sockaddr_ina *dst, int m) val->time = t; return 0; } - if (i < 0) { + val = mem_get(params.mempool, str, len); + if (!val) { return -1; } - val = params.mempool->values[i]; time(&t); if (t > val->time + params.cache_ttl) { LOG(LOG_S, "time=%ld, now=%ld, ignore\n", val->time, t); @@ -546,6 +538,19 @@ int mode_add_get(struct sockaddr_ina *dst, int m) } +int ext_connect(struct poolhd *pool, struct eval *val, + struct sockaddr_ina *dst, int next, int m) +{ + struct desync_params *dp = ¶ms.dp[m]; + if (dp->to_ip == 2) { + struct sockaddr_ina addr = { .in6 = dp->addr }; + addr.in.sin_port = dst->in.sin_port; + return create_conn(pool, val, &addr, next); + } + return create_conn(pool, val, dst, next); +} + + static inline int on_request(struct poolhd *pool, struct eval *val, char *buffer, size_t bfsize) { @@ -584,18 +589,26 @@ static inline int on_request(struct poolhd *pool, struct eval *val, } return -1; } - error = create_conn(pool, val, &dst, EV_CONNECT); + if (params.late_conn) { + val->type = EV_DESYNC; + if (resp_error(val->fd, 0, val->flag) < 0) { + perror("send"); + return -1; + } + val->in6 = dst.in6; + return 0; + } + int m = mode_add_get(&dst, -1); + val->cache = (m == 0); + val->attempt = m < 0 ? 0 : m; + + error = ext_connect(pool, val, &dst, EV_CONNECT, m); if (error) { int en = get_e(); if (resp_error(val->fd, en ? en : error, val->flag) < 0) uniperror("send"); return -1; } - int m = mode_add_get(&dst, -1); - if (m >= 0) { - val->attempt = m; - } - val->pair->attempt = m; val->type = EV_IGNORE; return 0; } @@ -605,8 +618,8 @@ int reconnect(struct poolhd *pool, struct eval *val, int m) { struct eval *client = val->pair; - if (create_conn(pool, client, - (struct sockaddr_ina *)&val->in6, EV_DESYNC)) { + if (ext_connect(pool, client, + (struct sockaddr_ina *)&val->in6, EV_DESYNC, m)) { return -1; } val->pair = 0; @@ -614,19 +627,34 @@ int reconnect(struct poolhd *pool, struct eval *val, int m) client->type = EV_IGNORE; client->attempt = m; + client->cache = 1; return 0; } +bool check_host(struct mphdr *hosts, struct eval *val) +{ + char *host; + int len; + if (!(len = parse_tls(val->buff.data, val->buff.size, &host))) { + len = parse_http(val->buff.data, val->buff.size, &host, 0); + } + return mem_get(hosts, host, len) != 0; +} + + int on_torst(struct poolhd *pool, struct eval *val) { int m = val->pair->attempt + 1; for (; m < params.dp_count; m++) { - struct desync_params dp = params.dp[m]; - if (dp.detect == 0 - || (dp.detect & DETECT_TORST)) + struct desync_params *dp = ¶ms.dp[m]; + if (!(dp->detect & DETECT_TORST)) { + continue; + } + if (!dp->hosts || check_host(dp->hosts, val->pair)) { break; + } } if (m >= params.dp_count) { mode_add_get( @@ -646,25 +674,34 @@ int on_response(struct poolhd *pool, struct eval *val, ssize_t qn = val->pair->buff.size; for (; m < params.dp_count; m++) { - struct desync_params dp = params.dp[m]; + struct desync_params *dp = ¶ms.dp[m]; - if ((dp.detect & DETECT_HTTP_LOCAT) - && is_http_redirect(req, qn, resp, sn)) { - break; - } - if ((dp.detect & DETECT_TLS_INVSID) - && neq_tls_sid(req, qn, resp, sn)) { - break; - } - if ((dp.detect & DETECT_TLS_ALERT) - && is_tls_alert(resp, sn)) { - break; - } - if (dp.detect & DETECT_HTTP_CLERR) { - int code = get_http_code(resp, sn); - if (code > 400 && code < 451 && code != 429) { + switch (0) { + default: + if ((dp->detect & DETECT_HTTP_LOCAT) + && is_http_redirect(req, qn, resp, sn)) { break; } + else if ((dp->detect & DETECT_TLS_INVSID) + && neq_tls_sid(req, qn, resp, sn) + && !neq_tls_sid( + fake_tls.data, fake_tls.size, resp, sn)) { + break; + } + else if ((dp->detect & DETECT_TLS_ALERT) + && is_tls_alert(resp, sn)) { + break; + } + else if (dp->detect & DETECT_HTTP_CLERR) { + int code = get_http_code(resp, sn); + if (code > 400 && code < 451 && code != 429) { + break; + } + } + continue; + } + if (!dp->hosts || check_host(dp->hosts, val->pair)) { + break; } } if (m < params.dp_count) { @@ -715,8 +752,7 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val, } int m = pair->attempt; - if ((m == 0 && val->attempt < 0) - || (m && m == val->attempt)) { + if (!pair->cache) { return 0; } if (m == 0) { @@ -757,6 +793,21 @@ int on_desync(struct poolhd *pool, struct eval *val, return -1; } memcpy(val->buff.data, buffer, n); + + if (!m) for (; m < params.dp_count; m++) { + struct desync_params *dp = ¶ms.dp[m]; + if (!dp->detect && + (!dp->hosts || check_host(dp->hosts, val))) { + break; + } + } + if (m >= params.dp_count) return -1; + val->attempt = m; + + if (params.late_conn) { + return ext_connect(pool, val, + (struct sockaddr_ina *)&val->in6, EV_DESYNC, m); + } } else { n = val->buff.size; diff --git a/readme.txt b/readme.txt index f9cf62f..44795bb 100644 --- a/readme.txt +++ b/readme.txt @@ -40,7 +40,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s Если сервер его поддерживает, то первый пакет будет отправлен сразу вместе с SYN Поддерживается только в Linux (4.11+) --A, --auto[=t,r,c,s,a] +-L, --late-conn + Выполнять настоящее подключение только после получения первого пакета от клиента + Полезно при сочетании --hosts с --dst + +-A, --auto[=t,r,c,s,a,n] Автоматический режим Если произошло событие, похожее на блокировку или поломку, то будут применены параметры обхода, следующие за данной опцией @@ -50,11 +54,12 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s cl_err : HTTP ответ, код которого равен 40x, но не 429 sid_inv : session_id в TLS ServerHello и ClientHello не совпадают alert : TLS Error Alert в ответе + nop : Предыдущая группа пропущена, например из-за ограничения по hosts По умолчанию обрабатывается только torst Можно указывать несколько групп опций, раделяя их данным параметром Если соединение успешно прошло, то параметры для данного IP будут закешированны Параметры, которые можно вынести в отдельную группу: - split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec + hosts, dst, split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec Пример: --auto=redirect --split=1+h --auto=torst --fake -1 --auto=sid_inv,alert --tlsrec 1+s @@ -66,6 +71,14 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s В Linux переводится в миллисекунды, поэтому можно указать дробное число Истечение таймаута будет обработано --auto +-H, --hosts + Ограничить область действия параметров списком доменов + Домены должны быть разделены новой строкой или пробелом + +-D, --dst + Заменить адрес назначения из запроса на указанный + Полезно совмещать с --auto и --hosts + -s, --split Разбить запрос по указанному смещению После числа можно добавить флаг: