diff --git a/desync.c b/desync.c index fb6232a..307854d 100644 --- a/desync.c +++ b/desync.c @@ -12,6 +12,7 @@ #ifdef __linux__ #include #include + #include #ifdef MFD_CLOEXEC #include @@ -26,6 +27,7 @@ #include #include #endif +#define STR_MODE #include #include @@ -80,27 +82,23 @@ static inline void delay(long ms) void wait_send(int sfd) { for (int i = 0; params.wait_send; i++) { - struct { - uint8_t state; - uint8_t r[3]; - uint32_t rr[35]; - uint32_t notsent_bytes; - } tcpi = {}; + struct tcpi tcpi = {}; socklen_t ts = sizeof(tcpi); + if (getsockopt(sfd, IPPROTO_TCP, TCP_INFO, (char *)&tcpi, &ts) < 0) { perror("getsockopt TCP_INFO"); break; } + if (tcpi.state != 1) { + LOG(LOG_E, "state: %d\n", tcpi.state); + return; + } if (ts < sizeof(tcpi)) { LOG(LOG_E, "tcpi_notsent_bytes not provided\n"); params.wait_send = 0; break; } - if (tcpi.state != 1) { - LOG(LOG_E, "state: %d\n", tcpi.state); - return; - } if (tcpi.notsent_bytes == 0) { return; } @@ -109,12 +107,15 @@ void wait_send(int sfd) } delay(params.sfdelay); } +#define wait_send_if_support(sfd) \ + if (params.wait_send) wait_send(sfd) #else #define wait_send(sfd) delay(params.sfdelay) +#define wait_send_if_support(sfd) // :( #endif #ifdef __linux__ -int send_fake(int sfd, char *buffer, +ssize_t send_fake(int sfd, char *buffer, int cnt, long pos, int fa, struct desync_params *opt) { struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http; @@ -126,9 +127,9 @@ int send_fake(int sfd, char *buffer, return -1; } char *p = 0; - int status = -1; + ssize_t len = -1; - while (status) { + while (1) { if (ftruncate(ffd, pos) < 0) { uniperror("ftruncate"); break; @@ -150,7 +151,8 @@ int send_fake(int sfd, char *buffer, perror("setsockopt IP_OPTIONS"); break; } - if (sendfile(sfd, ffd, 0, pos) < 0) { + len = sendfile(sfd, ffd, 0, pos); + if (len < 0) { uniperror("sendfile"); break; } @@ -166,16 +168,16 @@ int send_fake(int sfd, char *buffer, perror("setsockopt IP_OPTIONS"); break; } - status = 0; + break; } if (p) munmap(p, pos); close(ffd); - return status; + return len; } #endif #ifdef _WIN32 -int send_fake(int sfd, char *buffer, +ssize_t send_fake(int sfd, char *buffer, int cnt, long pos, int fa, struct desync_params *opt) { struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http; @@ -202,9 +204,9 @@ int send_fake(int sfd, char *buffer, } OVERLAPPED ov = {}; - int status = -1; + ssize_t len = -1; - while (status) { + while (1) { ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ov.hEvent) { uniperror("CreateEvent"); @@ -235,7 +237,7 @@ int send_fake(int sfd, char *buffer, if (opt->ip_options && setsockopt(sfd, IPPROTO_IP, IP_OPTIONS, opt->ip_options, opt->ip_options_len) < 0) { - perror("setsockopt IP_OPTIONS"); + uniperror("setsockopt IP_OPTIONS"); break; } if (!TransmitFile(sfd, hfile, pos, pos, &ov, @@ -246,7 +248,7 @@ int send_fake(int sfd, char *buffer, break; } } - delay(params.sfdelay); + wait_send(sfd); if (SetFilePointer(hfile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { uniperror("SetFilePointer"); @@ -262,10 +264,11 @@ int send_fake(int sfd, char *buffer, if (opt->ip_options && setsockopt(sfd, IPPROTO_IP, IP_OPTIONS, opt->ip_options, 0) < 0) { - perror("setsockopt IP_OPTIONS"); + uniperror("setsockopt IP_OPTIONS"); break; } - status = 0; + len = pos; + break; } if (!CloseHandle(hfile)) { uniperror("CloseHandle hfile"); @@ -273,11 +276,11 @@ int send_fake(int sfd, char *buffer, if (ov.hEvent && !CloseHandle(ov.hEvent)) { uniperror("CloseHandle hEvent"); } - return status; + return len; } #endif -int send_oob(int sfd, char *buffer, +ssize_t send_oob(int sfd, char *buffer, ssize_t n, long pos) { ssize_t size = oob_data.size - 1; @@ -286,42 +289,53 @@ int send_oob(int sfd, char *buffer, char rchar = buffer[pos]; buffer[pos] = oob_data.data[0]; - if (send(sfd, buffer, pos + 1, MSG_OOB) < 0) { + ssize_t len = send(sfd, buffer, pos + 1, MSG_OOB); + buffer[pos] = rchar; + + if (len < 0) { uniperror("send"); - buffer[pos] = rchar; return -1; } - buffer[pos] = rchar; - wait_send(sfd); - + len--; + if (len != pos) { + return len; + } + if (size) { + wait_send(sfd); + } for (long i = 0; i < size; i++) { if (send(sfd, data + i, 1, MSG_OOB) < 0) { uniperror("send"); - return -1; + if (get_e() == EAGAIN) { + return len; + } + } + if (size != 1) { + wait_send(sfd); } - wait_send(sfd); } - return 0; + return len; } -int send_disorder(int sfd, +ssize_t send_disorder(int sfd, char *buffer, long pos, int fa) { int bttl = 1; - int status = 0; if (setttl(sfd, bttl, fa) < 0) { return -1; } - if (send(sfd, buffer, pos, 0) < 0) { + ssize_t len = send(sfd, buffer, pos, 0); + if (len < 0) { uniperror("send"); - status = -1; } + wait_send_if_support(sfd); + if (setttl(sfd, params.def_ttl, fa) < 0) { return -1; } - return status; + return len; } @@ -333,7 +347,7 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize, char *host = 0; int len = 0, type = 0; int fa = get_family(dst); - + // parse packet if ((len = parse_tls(buffer, n, &host))) { type = IS_HTTPS; } @@ -344,7 +358,7 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize, LOG(LOG_S, "host: %.*s (%ld)\n", len, host, host - buffer); } - + // modify packet if (type == IS_HTTP && dp.mod_http) { LOG(LOG_S, "modify HTTP: n=%ld\n", n); if (mod_http(buffer, n, dp.mod_http)) { @@ -378,19 +392,22 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize, lp = pos + 5; } } - + // set custom TTL if (params.custom_ttl) { if (setttl(sfd, params.def_ttl, fa) < 0) { return -1; } } + // desync long lp = offset; if (!type && params.de_known) { + // cancel } else for (int i = 0; i < dp.parts_n; i++) { struct part part = dp.parts[i]; + // change pos long pos = part.pos; if (part.flag == OFFSET_SNI) { if (type != IS_HTTPS) @@ -415,39 +432,46 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize, LOG(LOG_E, "split cancel: pos=%ld-%ld, n=%ld\n", lp, pos, n); break; } - LOG(LOG_S, "split: pos=%ld-%ld, m=%d\n", lp, pos, part.m); + // send part + LOG(LOG_S, "split: pos=%ld-%ld, m: %s\n", lp, pos, demode_str[part.m]); - int s = 0; + ssize_t s = 0; switch (part.m) { - #ifdef FAKE_SUPPORT - case DESYNC_FAKE: - s = send_fake(sfd, - buffer + lp, type, pos - lp, fa, &dp); - break; - #endif - case DESYNC_DISORDER: - s = send_disorder(sfd, - buffer + lp, pos - lp, fa); - break; - - case DESYNC_OOB: - s = send_oob(sfd, - buffer + lp, n - lp, pos - lp); - break; + #ifdef FAKE_SUPPORT + case DESYNC_FAKE: + s = send_fake(sfd, + buffer + lp, type, pos - lp, fa, &dp); + break; + #endif + case DESYNC_DISORDER: + s = send_disorder(sfd, + buffer + lp, pos - lp, fa); + break; - case DESYNC_SPLIT: - default: - s = send(sfd, buffer + lp, pos - lp, 0); + case DESYNC_OOB: + s = send_oob(sfd, + buffer + lp, n - lp, pos - lp); + wait_send_if_support(sfd); + break; + + case DESYNC_SPLIT: + default: + s = send(sfd, buffer + lp, pos - lp, 0); + wait_send_if_support(sfd); } if (s < 0) { - if (part.m != DESYNC_FAKE - && get_e() == EAGAIN) { + if (get_e() == EAGAIN) { return lp; } return -1; + } + else if (s != (pos - lp)) { + LOG(LOG_E, "%ld != %ld\n", s, pos - lp); + return lp + s; } lp = pos; } + // send all/rest if (lp < n) { LOG((lp ? LOG_S : LOG_L), "send: pos=%ld-%ld\n", lp, n); if (send(sfd, buffer + lp, n - lp, 0) < 0) { diff --git a/desync.h b/desync.h index 9e480e9..89989a6 100644 --- a/desync.h +++ b/desync.h @@ -1 +1,10 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize, ssize_t n, ssize_t offset, struct sockaddr *dst, int dp_c); + +struct tcpi { + uint8_t state; + uint8_t r[3]; + uint32_t rr[5]; + uint32_t unacked; + uint32_t rrr[29]; + uint32_t notsent_bytes; +}; \ No newline at end of file diff --git a/main.c b/main.c index 289adeb..68f0b04 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,7 @@ #define close(fd) closesocket(fd) #endif -#define VERSION 6 +#define VERSION 7 #define MPOOL_INC 16 @@ -35,6 +35,7 @@ fake_http = { oob_data = { 1, "a" }; +char ip_option[1] = "\0"; struct params params = { @@ -65,7 +66,7 @@ const char help_text[] = { " -N, --no-domain Deny domain resolving\n" " -I --conn-ip Connection binded IP, default ::\n" " -b, --buf-size Buffer size, default 16384\n" - " -x, --debug Print logs, 0, 1 or 2\n" + " -x, --debug Print logs, 0, 1 or 2\n" " -g, --def-ttl TTL for all outgoing connections\n" // desync options " -K, --desync-known Desync only HTTP and TLS with SNI\n" @@ -86,7 +87,7 @@ const char help_text[] = { #ifdef FAKE_SUPPORT " -f, --fake Split and send fake packet\n" " -t, --ttl TTL of fake packets, default 8\n" - " -k, --ip-opt IP options of fake packets\n" + " -k, --ip-opt [f|:str] IP options of fake packets\n" " -l, --fake-tls \n" " -j, --fake-http Set custom fake packet\n" " -n, --tls-sni Change SNI in fake ClientHello\n" @@ -125,7 +126,7 @@ const struct option options[] = { #ifdef FAKE_SUPPORT {"fake", 1, 0, 'f'}, {"ttl", 1, 0, 't'}, - {"ip-opt", 1, 0, 'k'}, + {"ip-opt", 2, 0, 'k'}, {"fake-tls", 1, 0, 'l'}, {"fake-http", 1, 0, 'j'}, {"tls-sni", 1, 0, 'n'}, @@ -489,7 +490,12 @@ int main(int argc, char **argv) break; case 'k': - dp->ip_options = ftob(optarg, &dp->ip_options_len); + if (optarg) + dp->ip_options = ftob(optarg, &dp->ip_options_len); + else { + dp->ip_options = ip_option; + dp->ip_options_len = sizeof(ip_option); + } if (!dp->ip_options) { uniperror("read/parse"); return -1; @@ -573,7 +579,7 @@ int main(int argc, char **argv) } break; - case 'w': // + case 'V': // params.sfdelay = strtol(optarg, &end, 0); if (params.sfdelay < 0 || optarg == end || params.sfdelay >= 1000 || *end) diff --git a/params.h b/params.h index 17f9e39..c06a47e 100644 --- a/params.h +++ b/params.h @@ -23,6 +23,16 @@ enum demode { DESYNC_FAKE }; +#ifdef STR_MODE +char *demode_str[] = { + "DESYNC_NONE", + "DESYNC_SPLIT", + "DESYNC_DISORDER", + "DESYNC_OOB", + "DESYNC_FAKE" +}; +#endif + struct part { int m; int flag; @@ -76,4 +86,6 @@ extern struct packet oob_data; struct spos { ssize_t start, end, size; char *data; -}; \ No newline at end of file +}; + +extern char ip_option[1]; \ No newline at end of file diff --git a/readme.txt b/readme.txt index 7c74c79..8bfa865 100644 --- a/readme.txt +++ b/readme.txt @@ -35,6 +35,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s Отключить запутывание для нераспознанных протоколов Распознаваемые протоколы: HTTP и TLS с SNI +-F, --tfo + Включает TCP Fast Open + Если сервер его поддерживает, то первый пакет будет отправлен сразу вместе с SYN + Поддерживается только в Linux (4.11+) + -A, --auto Автоматический режим Если сервер сбросил подключение, превышено время ожидания, сработал --tr, @@ -42,7 +47,7 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s Можно указывать несколько групп параметров, раделяя их данным флагом Если соединение успешно прошло, то параметры для данного IP будут закешированны Параметры, которые можно вынести в отдельную группу: - split, disorder, oob, fake, ttl, mod-http, tlsrec + split, disorder, oob, fake, ttl, ip-opt, mod-http, tlsrec -u, --cache-ttl Время жизни значения в кеше, по умолчанию 100800 (28 часов) @@ -79,6 +84,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s TTL для поддельного пакета, по умолчанию 8 Необходимо подобрать такое значение, чтобы пакет не дошел до сервера, но был обработан DPI +-k, --ip-opt [file|:str] + Установить опции для фейкового IP пакета + Существенно снизит вероятность, что пакет дойдет до сервера + Стоит учесть, что до DPI он также может не дойти + -l, --fake-tls -j, --fake-http Указать свои поддельные пакеты, вместо дефолтных