Auto mode

This commit is contained in:
ruti 2024-03-08 03:37:02 +03:00
parent 4e28fbeaae
commit 19171cfeca
11 changed files with 367 additions and 102 deletions

View File

@ -1,7 +1,7 @@
TARGET = ciadpi
CC ?= gcc
CFLAGS += -std=c99 -O2 -D_XOPEN_SOURCE=500
SOURCES = packets.c main.c conev.c proxy.c desync.c
SOURCES = packets.c main.c conev.c proxy.c desync.c mpool.c
all:
$(CC) $(CFLAGS) $(SOURCES) -I . -o $(TARGET)

18
conev.c
View File

@ -43,15 +43,11 @@ struct eval *add_event(struct poolhd *pool, enum eid type,
if (pool->count >= pool->max)
return 0;
struct eval *val = pool->links[pool->count];
memset(val, 0, sizeof(*val));
val->fd = fd;
val->index = pool->count;
val->type = type;
val->pair = 0;
val->tmpbuf = 0;
val->size = 0;
val->offset = 0;
val->flag = 0;
#ifndef NOEPOLL
struct epoll_event ev = {
@ -79,9 +75,9 @@ void del_event(struct poolhd *pool, struct eval *val)
if (!val->fd) {
return;
}
if (val->tmpbuf) {
free(val->tmpbuf);
val->tmpbuf = 0;
if (val->buff.data) {
free(val->buff.data);
val->buff.data = 0;
}
close(val->fd);
val->fd = 0;
@ -116,9 +112,9 @@ void destroy_pool(struct poolhd *pool)
close(val->fd);
val->fd = 0;
}
if (val->tmpbuf) {
free(val->tmpbuf);
val->tmpbuf = 0;
if (val->buff.data) {
free(val->buff.data);
val->buff.data = 0;
}
}
if (pool->items) {

18
conev.h
View File

@ -33,7 +33,8 @@ enum eid {
EV_REQUEST,
EV_CONNECT,
EV_IGNORE,
EV_TUNNEL
EV_TUNNEL,
EV_DESYNC
};
#define FLAG_S4 1
@ -46,23 +47,30 @@ char *eid_name[] = {
"EV_REQUEST",
"EV_CONNECT",
"EV_IGNORE",
"EV_TUNNEL"
"EV_TUNNEL",
"EV_DESYNC"
};
#endif
struct buffer {
ssize_t size;
int offset;
char *data;
};
struct eval {
int fd;
int index;
enum eid type;
struct eval *pair;
char *tmpbuf;
ssize_t size;
int offset;
struct buffer buff;
int flag;
union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
};
ssize_t recv_count;
int try_count;
#ifndef NOEPOLL
uint32_t events;
#endif

View File

@ -81,7 +81,7 @@ static inline void delay(long ms)
#ifndef _WIN32
int send_fake(int sfd, char *buffer,
int cnt, long pos, int fa)
int cnt, long pos, int fa, int ttl)
{
struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http;
size_t psz = pkt.size;
@ -107,7 +107,7 @@ int send_fake(int sfd, char *buffer,
}
memcpy(p, pkt.data, psz < pos ? psz : pos);
if (setttl(sfd, params.ttl, fa) < 0) {
if (setttl(sfd, ttl, fa) < 0) {
break;
}
if (_sendfile(sfd, ffd, 0, pos) < 0) {
@ -178,8 +178,10 @@ int send_disorder(int sfd,
int desync(int sfd, char *buffer, size_t bfsize,
ssize_t n, struct sockaddr *dst)
ssize_t n, struct sockaddr *dst, int dp_c)
{
struct desync_params dp = params.dp[dp_c];
char *host = 0;
int len = 0, type = 0;
int fa = get_family(dst);
@ -195,17 +197,17 @@ int desync(int sfd, char *buffer, size_t bfsize,
len, host, host - buffer);
}
if (type == IS_HTTP && params.mod_http) {
if (type == IS_HTTP && dp.mod_http) {
LOG(LOG_S, "modify HTTP: n=%ld\n", n);
if (mod_http(buffer, n, params.mod_http)) {
if (mod_http(buffer, n, dp.mod_http)) {
LOG(LOG_E, "mod http error\n");
return -1;
}
}
else if (type == IS_HTTPS && params.tlsrec_n) {
else if (type == IS_HTTPS && dp.tlsrec_n) {
long lp = 0;
for (int i = 0; i < params.tlsrec_n; i++) {
struct part part = params.tlsrec[i];
for (int i = 0; i < dp.tlsrec_n; i++) {
struct part part = dp.tlsrec[i];
long pos = part.pos + i * 5;
if (part.flag == OFFSET_SNI) {
@ -238,8 +240,8 @@ int desync(int sfd, char *buffer, size_t bfsize,
if (!type && params.de_known) {
}
else for (int i = 0; i < params.parts_n; i++) {
struct part part = params.parts[i];
else for (int i = 0; i < dp.parts_n; i++) {
struct part part = dp.parts[i];
long pos = part.pos;
if (part.flag == OFFSET_SNI) {
@ -268,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);
buffer + lp, type, pos - lp, fa, dp.ttl);
break;
#endif
case DESYNC_DISORDER:

View File

@ -1 +1 @@
int desync(int sfd, char *buffer, size_t bfsize, ssize_t n, struct sockaddr *dst);
int desync(int sfd, char *buffer, size_t bfsize, ssize_t n, struct sockaddr *dst, int dp_c);

58
main.c
View File

@ -17,13 +17,16 @@
#include <netdb.h>
#include <fcntl.h>
#ifdef __linux__
#define FAKE_SUPPORT 1
#endif
#else
#include <ws2tcpip.h>
#define close(fd) closesocket(fd)
#endif
#define VERSION 5
#define MPOOL_INC 16
struct packet fake_tls = {
@ -37,17 +40,10 @@ oob_data = {
};
struct params params = {
.ttl = 8,
.parts_n = 0,
.parts = 0,
.sfdelay = 3,
.def_ttl = 0,
.custom_ttl = 0,
.mod_http = 0,
.tlsrec = 0,
.tlsrec_n = 0,
.de_known = 0,
.ipv6 = 1,
@ -72,6 +68,7 @@ const char help_text[] = {
" -g, --def-ttl <num> TTL for all outgoing connections\n"
// desync options
" -K, --desync-known Desync only HTTP and TLS with SNI\n"
" -A, --auto Try desync params after this option\n"
" -s, --split <n[+s]> Split packet at n\n"
" +s - add SNI offset\n"
" +h - add HTTP Host offset\n"
@ -103,6 +100,7 @@ const struct option options[] = {
{"debug", 1, 0, 'x'},
{"desync-known ", 0, 0, 'K'},
{"auto", 0, 0, 'A'},
{"split", 1, 0, 's'},
{"disorder", 1, 0, 'd'},
{"oob", 1, 0, 'o'},
@ -229,6 +227,23 @@ int parse_offset(struct part *part, const char *str)
}
struct desync_params *add_dparams(
struct desync_params **root, int *n)
{
struct desync_params *p = realloc(
*root, sizeof(struct desync_params) * (*n + 1));
if (!p) {
uniperror("realloc");
return 0;
}
*root = p;
*n = *n + 1;
p = &((*root)[(*n) - 1]);
memset(p, 0, sizeof(*p));
return p;
}
int main(int argc, char **argv)
{
#ifdef _WIN32
@ -268,6 +283,11 @@ int main(int argc, char **argv)
char *end = 0;
uint16_t port = htons(1080);
struct desync_params *dp = add_dparams(
&params.dp, &params.dp_count);
if (!dp) {
return -1;
}
while (!invalid && (rez = getopt_long_only(
argc, argv, opt, options, 0)) != -1) {
switch (rez) {
@ -333,13 +353,20 @@ int main(int argc, char **argv)
params.de_known = 1;
break;
case 'A':
dp = add_dparams(&params.dp, &params.dp_count);
if (!dp) {
return -1;
}
break;
case 's':
case 'd':
case 'o':
case 'f':
;
struct part *part = add_part(
&params.parts, &params.parts_n);
&dp->parts, &dp->parts_n);
if (!part) {
return -1;
}
@ -363,7 +390,7 @@ int main(int argc, char **argv)
if (val <= 0 || val > 255 || *end)
invalid = 1;
else
params.ttl = val;
dp->ttl = val;
break;
case 'n':
@ -403,13 +430,13 @@ int main(int argc, char **argv)
while (end && !invalid) {
switch (*end) {
case 'r':
params.mod_http |= MH_SPACE;
dp->mod_http |= MH_SPACE;
break;
case 'h':
params.mod_http |= MH_HMIX;
dp->mod_http |= MH_HMIX;
break;
case 'd':
params.mod_http |= MH_DMIX;
dp->mod_http |= MH_DMIX;
break;
default:
invalid = 1;
@ -421,7 +448,7 @@ int main(int argc, char **argv)
break;
case 'r':
part = add_part(&params.tlsrec, &params.tlsrec_n);
part = add_part(&dp->tlsrec, &dp->tlsrec_n);
if (!part) {
return -1;
}
@ -476,6 +503,11 @@ int main(int argc, char **argv)
return -1;
}
}
params.mempool = mem_pool(MPOOL_INC);
if (!params.mempool) {
uniperror("mem_pool");
return -1;
}
int status = run(&s);
#ifdef _WIN32
WSACleanup();

89
mpool.c Normal file
View File

@ -0,0 +1,89 @@
#include <stdlib.h>
#include <string.h>
#include <mpool.h>
struct mphdr *mem_pool(int count)
{
struct mphdr *hdr = malloc(sizeof(struct mphdr));
if (!hdr) {
return 0;
}
hdr->inc = count;
hdr->max = count;
hdr->count = 0;
hdr->values = malloc(sizeof(*hdr->values) * count);
if (!hdr->values) {
free(hdr);
hdr = 0;
}
return hdr;
}
int mem_index(struct mphdr *hdr, char *str, int len)
{
if (!hdr->count) {
return -2;
}
int s = 0, m, i;
int e = hdr->count - 1;
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));
}
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;
}
int pos = mem_index(hdr, str, len);
if (pos >= 0) {
return hdr->values[pos];
}
pos = -pos - 2;
struct elem *val = malloc(sizeof(struct elem) + len);
if (!val) {
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);
}
hdr->values[pos] = val;
hdr->count++;
return val;
}

14
mpool.h Normal file
View File

@ -0,0 +1,14 @@
struct elem {
int m;
int len;
char data[];
};
struct mphdr {
int max;
int inc;
int count;
struct elem **values;
};
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);

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <mpool.h>
#ifdef _WIN32
#include <ws2tcpip.h>
@ -23,17 +24,22 @@ struct part {
long pos;
};
struct params {
char de_known;
struct desync_params {
int ttl;
int parts_n;
struct part *parts;
long sfdelay;
int def_ttl;
char custom_ttl;
int mod_http;
int tlsrec_n;
struct part *tlsrec;
};
struct params {
char de_known;
int dp_count;
struct desync_params *dp;
long sfdelay;
int def_ttl;
char custom_ttl;
char ipv6;
char resolve;
@ -41,6 +47,7 @@ struct params {
int debug;
size_t bfsize;
struct sockaddr_in6 baddr;
struct mphdr *mempool;
};
extern struct params params;

218
proxy.c
View File

@ -434,73 +434,31 @@ static inline int on_accept(struct poolhd *pool, struct eval *val)
}
static inline int on_connect(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize, int e)
{
if (val->flag == FLAG_CONN) {
int error = 0;
socklen_t len = sizeof(error);
if (e) {
if (getsockopt(val->fd, SOL_SOCKET,
SO_ERROR, (char *)&error, &len)) {
uniperror("getsockopt SO_ERROR");
return -1;
}
}
if (resp_error(val->pair->fd,
error, val->pair->flag) < 0) {
uniperror("send");
return -1;
}
if (e) {
return -1;
}
if (mod_etype(pool, val, POLLOUT, 0)) {
uniperror("mod_etype");
return -1;
}
val->type = EV_TUNNEL;
val->pair->type = EV_CONNECT;
}
else {
ssize_t n = recv(val->fd, buffer, bfsize, 0);
if (n <= 0) {
if (n) uniperror("recv data");
return -1;
}
if (desync(val->pair->fd, buffer, bfsize,
n, (struct sockaddr *)&val->pair->in6)) {
return -1;
}
val->type = EV_TUNNEL;
}
return 0;
}
static inline int on_tunnel(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize, int out)
{
ssize_t n = 0;
struct eval *pair = val->pair;
if (pair->tmpbuf && out) {
if (pair->buff.size && out) {
pair = val;
val = val->pair;
n = val->size - val->offset;
ssize_t sn = send(pair->fd, val->tmpbuf + val->offset, n, 0);
n = val->buff.size - val->buff.offset;
ssize_t sn = send(pair->fd,
val->buff.data + val->buff.offset, n, 0);
if (sn != n) {
if (sn < 0 && get_e() != EAGAIN) {
uniperror("send");
return -1;
}
if (sn > 0)
val->offset += sn;
val->buff.offset += sn;
return 0;
}
free(val->tmpbuf);
val->tmpbuf = 0;
free(val->buff.data);
val->buff.data = 0;
val->buff.size = 0;
if (mod_etype(pool, val, POLLIN, 1) ||
mod_etype(pool, pair, POLLOUT, 0)) {
@ -516,6 +474,8 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
if (n) uniperror("recv");
return -1;
}
val->recv_count += n;
ssize_t sn = send(pair->fd, buffer, n, 0);
if (sn != n) {
if (sn < 0) {
@ -527,12 +487,12 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
}
LOG(LOG_S, "EAGAIN, set POLLOUT (fd: %d)\n", pair->fd);
val->size = n - sn;
if (!(val->tmpbuf = malloc(val->size))) {
val->buff.size = n - sn;
if (!(val->buff.data = malloc(val->buff.size))) {
uniperror("malloc");
return -1;
}
memcpy(val->tmpbuf, buffer + sn, val->size);
memcpy(val->buff.data, buffer + sn, val->buff.size);
if (mod_etype(pool, val, POLLIN, 0) ||
mod_etype(pool, pair, POLLOUT, 1)) {
@ -546,6 +506,150 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
}
int try_again(struct poolhd *pool, struct eval *val)
{
if (val->flag != FLAG_CONN) {
return -1;
}
if (val->recv_count) {
return -1;
}
struct eval *client = val->pair;
if (client->try_count >= 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);
if (e) {
return -1;
}
val->pair = 0;
del_event(pool, val);
client->type = EV_IGNORE;
client->try_count++;
return 0;
}
int mode_add_get(struct sockaddr_ina *dst, int m)
{
char *data;
int len;
if (dst->sa.sa_family == AF_INET) {
data = (char *)(&dst->in.sin_addr);
len = sizeof(dst->in.sin_addr);
} else {
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);
if (!val) {
uniperror("mem_add");
return -1;
}
val->m = m;
return 0;
}
int i = mem_index(params.mempool, data, len);
if (i < 0) {
return -1;
}
val = params.mempool->values[i];
return val->m;
}
int on_desync(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
ssize_t n;
int m;
if (val->flag == FLAG_CONN) {
if (on_tunnel(pool, val, buffer, bfsize, 0)) {
return try_again(pool, val);
}
free(val->pair->buff.data);
val->pair->buff.data = 0;
val->pair->buff.size = 0;
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;
}
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;
if (!(val->buff.data = malloc(n))) {
uniperror("malloc");
return -1;
}
memcpy(val->buff.data, buffer, n);
} else {
n = val->buff.size;
memcpy(buffer, val->buff.data, n);
}
if (desync(val->pair->fd, buffer, bfsize, n,
(struct sockaddr *)&val->pair->in6, m)) {
return -1;
}
val->type = EV_TUNNEL;
return 0;
}
static inline int on_connect(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize, int e)
{
int error = 0;
socklen_t len = sizeof(error);
if (e) {
if (getsockopt(val->fd, SOL_SOCKET,
SO_ERROR, (char *)&error, &len)) {
uniperror("getsockopt SO_ERROR");
return -1;
}
}
if (!val->pair->try_count) {
if (resp_error(val->pair->fd,
error, val->pair->flag) < 0) {
uniperror("send");
return -1;
}
}
if (e) {
return -1;
}
if (mod_etype(pool, val, POLLOUT, 0)) {
uniperror("mod_etype");
return -1;
}
val->type = EV_DESYNC;
val->pair->type = EV_DESYNC;
if (val->pair->try_count) {
return on_desync(pool, val->pair, buffer, bfsize);
}
return 0;
}
int event_loop(int srvfd)
{
size_t bfsize = params.bfsize;
@ -600,8 +704,9 @@ int event_loop(int srvfd)
case EV_TUNNEL:
if (on_tunnel(pool, val,
buffer, bfsize, etype & POLLOUT))
buffer, bfsize, etype & POLLOUT)) {
del_event(pool, val);
}
continue;
case EV_CONNECT:
@ -610,6 +715,11 @@ int event_loop(int srvfd)
del_event(pool, val);
continue;
case EV_DESYNC:
if (on_desync(pool, val, buffer, bfsize))
del_event(pool, val);
continue;
case EV_IGNORE:
if (etype & (POLLHUP | POLLERR | POLLRDHUP))
del_event(pool, val);

View File

@ -3,7 +3,7 @@
--------------
Использование:
$ ./ciadpi --disorder 3+sni
$ ./ciadpi --disorder 3 -A --tlsrec 1+s
Описание аргументов:
-i, --ip <ip>
@ -35,6 +35,13 @@ $ ./ciadpi --disorder 3+sni
Отключить запутывание для нераспознанных протоколов
Распознаваемые протоколы: HTTP и TLS с SNI
-A, --auto
Автоматический режим
Если обнаружены признаки блокировки (соединение разорвано сразу после первого пакета),
то будут применены параметры обхода, следующие за данной опцией
Можно указывать несколько групп параметров, раделяя их данным флагом
Если соединение успешно прошло, то параметры будут сохранены для данного IP до следующего перезапуска
-s, --split <n[+s]>
Разбить запрос по указанному смещению
После числа можно добавить флаг: