diff --git a/conev.h b/conev.h index e01c46f..5461530 100644 --- a/conev.h +++ b/conev.h @@ -34,6 +34,7 @@ enum eid { EV_CONNECT, EV_IGNORE, EV_TUNNEL, + EV_PRE_TUNNEL, EV_DESYNC }; @@ -48,6 +49,7 @@ char *eid_name[] = { "EV_CONNECT", "EV_IGNORE", "EV_TUNNEL", + "EV_PRE_TUNNEL", "EV_DESYNC" }; #endif @@ -71,6 +73,7 @@ struct eval { }; ssize_t recv_count; int try_count; + int saved_m; #ifndef NOEPOLL uint32_t events; #endif diff --git a/desync.c b/desync.c index e56ab8c..c569315 100644 --- a/desync.c +++ b/desync.c @@ -270,7 +270,7 @@ int desync(int sfd, char *buffer, size_t bfsize, #ifndef _WIN32 case DESYNC_FAKE: s = send_fake(sfd, - buffer + lp, type, pos - lp, fa, dp.ttl); + buffer + lp, type, pos - lp, fa, dp.ttl ? dp.ttl : 8); break; #endif case DESYNC_DISORDER: diff --git a/main.c b/main.c index eeafc9b..648aeda 100644 --- a/main.c +++ b/main.c @@ -46,6 +46,7 @@ struct params params = { .custom_ttl = 0, .de_known = 0, + .cache_ttl = 3600, .ipv6 = 1, .resolve = 1, .max_open = 512, @@ -69,6 +70,7 @@ const char help_text[] = { // desync options " -K, --desync-known Desync only HTTP and TLS with SNI\n" " -A, --auto Try desync params after this option\n" + " -u, --cache-ttl Lifetime of cached desync params for IP\n" " -s, --split Split packet at n\n" " +s - add SNI offset\n" " +h - add HTTP Host offset\n" @@ -101,6 +103,7 @@ const struct option options[] = { {"desync-known ", 0, 0, 'K'}, {"auto", 0, 0, 'A'}, + {"cache-ttl", 1, 0, 'u'}, {"split", 1, 0, 's'}, {"disorder", 1, 0, 'd'}, {"oob", 1, 0, 'o'}, @@ -360,6 +363,14 @@ int main(int argc, char **argv) } break; + case 'u': + val = strtol(optarg, &end, 0); + if (val <= 0 || *end) + invalid = 1; + else + params.cache_ttl = val; + break; + case 's': case 'd': case 'o': diff --git a/mpool.c b/mpool.c index b9386bf..10d14c2 100644 --- a/mpool.c +++ b/mpool.c @@ -50,7 +50,7 @@ int mem_index(struct mphdr *hdr, char *str, int len) } -struct elem *mem_add(struct mphdr *hdr, char *str, int len) +struct elem *mem_add(struct mphdr *hdr, char *str, int len, int pos) { int max = hdr->max; @@ -63,7 +63,6 @@ struct elem *mem_add(struct mphdr *hdr, char *str, int len) hdr->max = max; hdr->values = new; } - int pos = mem_index(hdr, str, len); if (pos >= 0) { return hdr->values[pos]; } @@ -87,3 +86,30 @@ struct elem *mem_add(struct mphdr *hdr, char *str, int len) hdr->count++; return val; } + + +void mem_delete(struct mphdr *hdr, int pos) +{ + int max = hdr->max; + if (!hdr->count) { + 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; + } + hdr->max = max; + hdr->values = new; + } + 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--; +} diff --git a/mpool.h b/mpool.h index 7293c2b..53c0b67 100644 --- a/mpool.h +++ b/mpool.h @@ -1,5 +1,8 @@ +#include + struct elem { int m; + time_t time; int len; char data[]; }; @@ -11,4 +14,5 @@ struct mphdr { }; 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); \ No newline at end of file +struct elem *mem_add(struct mphdr *hdr, char *str, int len, int pos); +void mem_delete(struct mphdr *hdr, int pos); \ No newline at end of file diff --git a/params.h b/params.h index 70620ff..09a36eb 100644 --- a/params.h +++ b/params.h @@ -41,6 +41,7 @@ struct params { int def_ttl; char custom_ttl; + long cache_ttl; char ipv6; char resolve; int max_open; diff --git a/proxy.c b/proxy.c index ec13eb9..7cf571c 100644 --- a/proxy.c +++ b/proxy.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -509,10 +510,6 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val, int try_again(struct poolhd *pool, struct eval *val) { struct eval *client = val->pair; - if (client->try_count + 1 >= params.dp_count) { - return -1; - } - LOG(LOG_S, "try next params: %d\n", client->try_count + 1); int e = create_conn(pool, client, (struct sockaddr_ina *)&val->in6); @@ -532,6 +529,9 @@ int mode_add_get(struct sockaddr_ina *dst, int m) { char *data; int len; + time_t t; + struct elem *val; + if (dst->sa.sa_family == AF_INET) { data = (char *)(&dst->in.sin_addr); len = sizeof(dst->in.sin_addr); @@ -539,68 +539,118 @@ int mode_add_get(struct sockaddr_ina *dst, int m) data = (char *)(&dst->in6.sin6_addr); len = sizeof(dst->in6.sin6_addr); } - struct elem *val; - if (m >= 0) { - val = mem_add(params.mempool, data, len); + int i = mem_index(params.mempool, data, len); + if (m == 0 && i >= 0) { + mem_delete(params.mempool, i); + return 0; + } + else if (m > 0) { + time(&t); + val = mem_add(params.mempool, data, len, i); if (!val) { uniperror("mem_add"); return -1; } val->m = m; + val->time = t; return 0; } - int i = mem_index(params.mempool, data, len); if (i < 0) { return -1; } val = params.mempool->values[i]; + time(&t); + if (t > val->time + params.cache_ttl) { + LOG(LOG_S, "cache value is too old, ignore\n"); + return -1; + } return val->m; } +int on_tunnel_check(struct poolhd *pool, struct eval *val, + char *buffer, size_t bfsize, int out) +{ + if (!out && val->flag == FLAG_CONN) { + int e = on_tunnel(pool, val, buffer, bfsize, out); + if (e) { + if (unie(e) != ECONNRESET) { + return -1; + } + if (val->pair->try_count + 1 >= params.dp_count) { + mode_add_get( + (struct sockaddr_ina *)&val->in6, 0); + 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; + + int m = pair->try_count; + if (m == 0 && !val->saved_m) { + return 0; + } + return mode_add_get( + (struct sockaddr_ina *)&val->in6, m); + } + else { + int e = on_tunnel(pool, val, buffer, bfsize, out); + if (e) { + if (val->flag == FLAG_CONN) { + val = val->pair; + } + int m = val->try_count + 1; + if (m >= params.dp_count) { + m = 0; + } + mode_add_get( + (struct sockaddr_ina *)&val->pair->in6, m); + return -1; + } + } + return 0; +} + + int on_desync(struct poolhd *pool, struct eval *val, char *buffer, size_t bfsize) { ssize_t n; int m; - if (val->flag == FLAG_CONN) { - int e = on_tunnel(pool, val, buffer, bfsize, 0); - if (e) { - if (unie(e) == ECONNRESET) { - return try_again(pool, val); - } - return -1; + if (!val->try_count) { + m = mode_add_get( + (struct sockaddr_ina *)&val->pair->in6, -1); + if (m >= 0) { + val->saved_m = m + 1; + val->try_count = m; } - free(val->pair->buff.data); - val->pair->buff.data = 0; - val->pair->buff.size = 0; - val->type = EV_TUNNEL; - - m = val->pair->try_count; - return mode_add_get( - (struct sockaddr_ina *)&val->in6, m); - } - m = mode_add_get( - (struct sockaddr_ina *)&val->pair->in6, -1); - if (m < 0) { - m = val->try_count; } + m = val->try_count; + LOG(LOG_S, "desync params index: %d\n", m); + if (!val->buff.data) { n = recv(val->fd, buffer, bfsize, 0); if (n <= 0) { if (n) uniperror("recv data"); return -1; } - val->recv_count += n; val->buff.size = n; + val->recv_count += n; if (!(val->buff.data = malloc(n))) { uniperror("malloc"); return -1; } memcpy(val->buff.data, buffer, n); - } else { + } + else { n = val->buff.size; memcpy(buffer, val->buff.data, n); } @@ -608,7 +658,8 @@ int on_desync(struct poolhd *pool, struct eval *val, (struct sockaddr *)&val->pair->in6, m)) { return -1; } - val->type = EV_TUNNEL; + val->type = EV_PRE_TUNNEL; + val->pair->type = EV_PRE_TUNNEL; return 0; } @@ -701,11 +752,16 @@ int event_loop(int srvfd) del_event(pool, val); continue; + case EV_PRE_TUNNEL: + if (on_tunnel_check(pool, val, + buffer, bfsize, etype & POLLOUT)) + del_event(pool, val); + continue; + case EV_TUNNEL: if (on_tunnel(pool, val, - buffer, bfsize, etype & POLLOUT)) { + buffer, bfsize, etype & POLLOUT)) del_event(pool, val); - } continue; case EV_CONNECT: diff --git a/readme.txt b/readme.txt index 09a5c49..1a9339a 100644 --- a/readme.txt +++ b/readme.txt @@ -40,7 +40,10 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s Если обнаружены признаки блокировки (соединение разорвано сразу после первого пакета), то будут применены параметры обхода, следующие за данной опцией Можно указывать несколько групп параметров, раделяя их данным флагом - Если соединение успешно прошло, то параметры будут сохранены для данного IP до следующего перезапуска + Если соединение успешно прошло, то параметры для данного IP будут закешированны + +-u, --cache-ttl + Время жизни значения в кеше, указывается в секундах -s, --split Разбить запрос по указанному смещению