--redirect

This commit is contained in:
ruti 2024-03-11 18:38:39 +03:00
parent 69286c71db
commit 015095d2ef
6 changed files with 299 additions and 141 deletions

View file

@ -35,12 +35,15 @@ enum eid {
EV_IGNORE,
EV_TUNNEL,
EV_PRE_TUNNEL,
EV_REDIRECT,
EV_DESYNC
};
#define FLAG_S4 1
#define FLAG_S5 2
#define FLAG_CONN 4
#define FLAG_AUTH 8
#define FLAG_ANSWER 16
#ifndef CONEV_H
char *eid_name[] = {
@ -50,6 +53,7 @@ char *eid_name[] = {
"EV_IGNORE",
"EV_TUNNEL",
"EV_PRE_TUNNEL",
"EV_REDIRECT",
"EV_DESYNC"
};
#endif
@ -72,8 +76,7 @@ struct eval {
struct sockaddr_in6 in6;
};
ssize_t recv_count;
int try_count;
int saved_m;
int attempt;
#ifndef NOEPOLL
uint32_t events;
#endif

View file

@ -181,7 +181,9 @@ int desync(int sfd, char *buffer, size_t bfsize,
ssize_t n, struct sockaddr *dst, int dp_c)
{
struct desync_params dp = params.dp[dp_c];
if (dp.redirect) {
dst = (struct sockaddr *)&dp.ext_proxy;
}
char *host = 0;
int len = 0, type = 0;
int fa = get_family(dst);
@ -296,7 +298,7 @@ int desync(int sfd, char *buffer, size_t bfsize,
lp = pos;
}
if (lp < n) {
LOG(LOG_S, "send: pos=%ld-%ld\n", lp, n);
LOG((lp ? LOG_S : LOG_L), "send: pos=%ld-%ld\n", lp, n);
if (send(sfd, buffer + lp, n - lp, 0) < 0) {
uniperror("send");
return -1;

46
main.c
View file

@ -46,7 +46,7 @@ struct params params = {
.custom_ttl = 0,
.de_known = 0,
.cache_ttl = 3600,
.cache_ttl = 21600,
.ipv6 = 1,
.resolve = 1,
.max_open = 512,
@ -71,6 +71,7 @@ const char help_text[] = {
" -K, --desync-known Desync only HTTP and TLS with SNI\n"
" -A, --auto Try desync params after this option\n"
" -u, --cache-ttl <sec> Lifetime of cached desync params for IP\n"
" -q, --redirect <ip:port> Redirect to external SOCKS5 proxy\n"
" -s, --split <n[+s]> Split packet at n\n"
" +s - add SNI offset\n"
" +h - add HTTP Host offset\n"
@ -119,7 +120,7 @@ const struct option options[] = {
{"tlsrec", 1, 0, 'r'},
{"def-ttl", 1, 0, 'g'},
{"delay", 1, 0, 'w'}, //
{"redirect", 1, 0, 'q'},
{0}
};
@ -156,15 +157,40 @@ char *ftob(char *name, ssize_t *sl)
}
int get_addr(const char *str, struct sockaddr_ina *addr)
int get_addr(char *str, struct sockaddr_ina *addr)
{
uint16_t port = 0;
char *s = str, *e = 0;
char *end = 0, *p = str;
if (*str == '[') {
e = strchr(str, ']');
if (!e) return -1;
s++; p = e + 1;
}
p = strchr(p, ':');
if (p) {
long val = strtol(p + 1, &end, 0);
if (val <= 0 || val > 0xffff || *end)
return -1;
else
port = htons(val);
if (!e) e = p;
}
if ((e - s) < 7) {
return -1;
}
char str_ip[(e - s) + 1];
memcpy(str_ip, s, e - s);
str_ip[e - s] = 0;
struct addrinfo hints = {0}, *res = 0;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(str, 0, &hints, &res) || !res) {
if (getaddrinfo(str_ip, 0, &hints, &res) || !res) {
return -1;
}
if (res->ai_addr->sa_family == AF_INET6)
@ -172,6 +198,10 @@ int get_addr(const char *str, struct sockaddr_ina *addr)
else
addr->in = *(struct sockaddr_in *)res->ai_addr;
freeaddrinfo(res);
if (port) {
addr->in6.sin6_port = port;
}
return 0;
}
@ -284,6 +314,7 @@ int main(int argc, char **argv)
long val = 0;
char *end = 0;
uint16_t port = htons(1080);
struct desync_params *dp = add_dparams(
@ -487,6 +518,13 @@ int main(int argc, char **argv)
invalid = 1;
break;
case 'q':
if (get_addr(optarg, (struct sockaddr_ina *)&dp->ext_proxy) < 0)
invalid = 1;
else
dp->redirect = 1;
break;
case 0:
break;

View file

@ -25,6 +25,8 @@ struct part {
};
struct desync_params {
char redirect;
struct sockaddr_in6 ext_proxy;
int ttl;
int parts_n;
struct part *parts;

363
proxy.c
View file

@ -263,7 +263,7 @@ int s5_get_addr(char *buffer, ssize_t n,
int create_conn(struct poolhd *pool,
struct eval *val, struct sockaddr_ina *dst)
struct eval *val, struct sockaddr_ina *dst, int next)
{
struct sockaddr_ina addr = *dst;
@ -319,7 +319,7 @@ int create_conn(struct poolhd *pool,
close(sfd);
return -1;
}
struct eval *pair = add_event(pool, EV_CONNECT, sfd, POLLOUT);
struct eval *pair = add_event(pool, next, sfd, POLLOUT);
if (!pair) {
close(sfd);
return -1;
@ -332,60 +332,6 @@ int create_conn(struct poolhd *pool,
}
static inline int on_request(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
struct sockaddr_ina dst = {0};
ssize_t n = recv(val->fd, buffer, bfsize, 0);
if (n < 1) {
if (n) uniperror("ss recv");
return -1;
}
if (*buffer == S_VER5) {
if (val->flag != FLAG_S5) {
if (auth_socks5(val->fd, buffer, n)) {
return -1;
}
val->flag = FLAG_S5;
return 0;
}
if (n < S_SIZE_MIN) {
LOG(LOG_E, "ss: request to small\n");
return -1;
}
int s5e = s5_get_addr(buffer, n, &dst);
if (!s5e &&
create_conn(pool, val, &dst)) {
s5e = S_ER_GEN;
}
if (s5e) {
resp_s5_error(val->fd, s5e);
return -1;
}
}
else if (*buffer == S_VER4) {
val->flag = FLAG_S4;
int error = s4_get_addr(buffer, n, &dst);
if (!error) {
error = create_conn(pool, val, &dst);
}
if (error) {
if (resp_error(val->fd, error, FLAG_S4) < 0)
uniperror("send");
return -1;
}
}
else {
LOG(LOG_E, "ss: invalid version: 0x%x (%lu)\n", *buffer, n);
return -1;
}
val->type = EV_IGNORE;
return 0;
}
static inline int on_accept(struct poolhd *pool, struct eval *val)
{
struct sockaddr_ina client;
@ -507,26 +453,9 @@ 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;
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)
{
// m < 0: get, m > 0: set, m == 0: delete
char *data;
int len;
time_t t;
@ -561,28 +490,130 @@ int mode_add_get(struct sockaddr_ina *dst, int m)
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;
LOG(LOG_S, "time=%ld, now=%ld, ignore\n", val->time, t);
return 0;
}
return val->m;
}
static inline int on_request(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
struct sockaddr_ina dst = {0};
ssize_t n = recv(val->fd, buffer, bfsize, 0);
if (n < 1) {
if (n) uniperror("ss recv");
return -1;
}
int e = 0, s5e = 0, m;
if (*buffer == S_VER5) {
if (val->flag != FLAG_S5) {
if (auth_socks5(val->fd, buffer, n)) {
return -1;
}
val->flag = FLAG_S5;
return 0;
}
if (n < S_SIZE_MIN) {
LOG(LOG_E, "ss: request to small\n");
return -1;
}
e = s5_get_addr(buffer, n, &dst);
s5e = e;
}
else if (*buffer == S_VER4) {
val->flag = FLAG_S4;
e = s4_get_addr(buffer, n, &dst);
}
else {
LOG(LOG_E, "ss: invalid version: 0x%x (%lu)\n", *buffer, n);
return -1;
}
if (!e) {
m = mode_add_get(&dst, -1);
int next = EV_CONNECT;
if (m >= 0) {
struct desync_params *dp = &params.dp[m];
if (dp->redirect) {
next = EV_REDIRECT;
e = create_conn(pool, val,
(struct sockaddr_ina *)&dp->ext_proxy, next);
val->pair->in6 = dst.in6;
}
}
if (next == EV_CONNECT) {
e = create_conn(pool, val, &dst, next);
}
}
if (e) {
if (s5e) {
resp_s5_error(val->fd, s5e);
}
else if (resp_error(val->fd, e, val->flag) < 0) {
uniperror("ss: send");
}
return -1;
}
if (m >= 0) {
val->attempt = m;
}
val->pair->attempt = m;
val->type = EV_IGNORE;
return 0;
}
int try_again(struct poolhd *pool, struct eval *val)
{
struct eval *client = val->pair;
int e = 0;
int m = client->attempt + 1;
if (m >= params.dp_count) {
mode_add_get(
(struct sockaddr_ina *)&val->in6, 0);
return -1;
}
struct desync_params *dp = &params.dp[m];
if (dp->redirect) {
e = create_conn(pool, client,
(struct sockaddr_ina *)&dp->ext_proxy, EV_REDIRECT);
client->pair->in6 = val->in6;
}
else {
e = create_conn(pool, client,
(struct sockaddr_ina *)&val->in6, EV_DESYNC);
}
if (e) {
return -1;
}
val->pair = 0;
del_event(pool, val);
client->type = EV_IGNORE;
client->attempt++;
return 0;
}
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 (val->flag == FLAG_CONN) {
if (out) {
return e;
}
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);;
return try_again(pool, val);
}
struct eval *pair = val->pair;
val->type = EV_TUNNEL;
@ -592,48 +623,37 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
pair->buff.data = 0;
pair->buff.size = 0;
int m = pair->try_count;
if (m == 0 && !val->saved_m) {
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);
}
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;
return e;
}
int on_desync(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
if (val->flag == FLAG_CONN) {
if (mod_etype(pool, val, POLLOUT, 0)) {
uniperror("mod_etype");
return -1;
}
val = val->pair;
}
ssize_t n;
int m;
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;
}
}
m = val->try_count;
LOG(LOG_S, "desync params index: %d\n", m);
int m = val->attempt;
LOG((m ? LOG_S : LOG_L), "desync params index: %d\n", m);
if (!val->buff.data) {
n = recv(val->fd, buffer, bfsize, 0);
@ -664,39 +684,120 @@ int on_desync(struct poolhd *pool, struct eval *val,
}
static inline int on_connect(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize, int e)
static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
{
int error = 0;
socklen_t len = sizeof(error);
struct eval *pair = val->pair;
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 (unie(error) == ECONNREFUSED) {
e = try_again(pool, val);
if (!e) error = 0;
}
}
if (e) {
return -1;
}
else {
if (mod_etype(pool, val, POLLOUT, 0)) {
uniperror("mod_etype");
return -1;
}
val->type = EV_DESYNC;
val->type = EV_TUNNEL;
val->pair->type = EV_DESYNC;
}
if (resp_error(pair->fd,
error, pair->flag) < 0) {
uniperror("send");
return -1;
}
return e ? -1 : 0;
}
if (val->pair->try_count) {
static inline int on_redirect(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
struct eval *pair = val->pair;
int e = -1;
switch (val->flag) {
case FLAG_CONN:;
char a[3] = "\5\1\0";
if (send(val->fd, &a, sizeof(a), 0) < 0) {
uniperror("rr: send");
break;
}
if (mod_etype(pool, val, POLLOUT, 0)) {
uniperror("mod_etype");
break;
}
val->flag = FLAG_AUTH;
return 0;
case FLAG_AUTH:;
ssize_t n = recv(val->fd, buffer, bfsize, 0);
if (n < 2) {
break;
}
if (!(buffer[0] == 5 && buffer[1] == 0)) {
LOG(LOG_E, "rr: auth error: 0x%x\n", buffer[1]);
break;
}
struct s5_req r = {.ver = 5, .cmd = S_CMD_CONN};
switch (val->in.sin_family) {
case AF_INET:
r.atp = S_ATP_I4;
r.i4 = val->in.sin_addr;
r.p4 = val->in.sin_port;
break;
case AF_INET6:
r.atp = S_ATP_I6;
r.i6 = val->in6.sin6_addr;
r.p6 = val->in6.sin6_port;
break;
default:
return -1;
}
if (send(val->fd, &r, sizeof(r), 0) < 0) {
uniperror("rr: send");
break;
}
val->flag = FLAG_ANSWER;
return 0;
case FLAG_ANSWER:
n = recv(val->fd, buffer, bfsize, 0);
if (n < sizeof(struct s5_rep)) {
uniperror("rr: recv");
break;
}
struct s5_rep *rr = (struct s5_rep *)buffer;
if (rr->ver != 5 || rr->code != 0) {
LOG(LOG_E, "rr: socks returned: %d\n", rr->code);
break;
}
val->flag = FLAG_CONN;
val->type = EV_TUNNEL;
pair->type = EV_DESYNC;
e = 0;
}
char is_first = (val->attempt == pair->attempt);
if (!e && !is_first) {
return on_desync(pool, val->pair, buffer, bfsize);
}
return 0;
else if (e) {
e = try_again(pool, val);
}
if (is_first && resp_error(pair->fd,
e, pair->flag) < 0) {
return -1;
}
return e;
}
@ -765,8 +866,12 @@ int event_loop(int srvfd)
continue;
case EV_CONNECT:
if (on_connect(pool, val,
buffer, bfsize, etype & POLLERR))
if (on_connect(pool, val, etype & POLLERR))
del_event(pool, val);
continue;
case EV_REDIRECT:
if (on_redirect(pool, val, buffer, bfsize))
del_event(pool, val);
continue;

View file

@ -37,14 +37,22 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
-A, --auto
Автоматический режим
Если обнаружены признаки блокировки (соединение разорвано сразу после первого пакета),
Если будет выполнено одно из следующих условий,
то будут применены параметры обхода, следующие за данной опцией
Условия:
- Сервер сбросил подключение, не отправив ответ
- Сервер прислал RST на этапе подключения
- Резервный прокси отказывает в соединении
Можно указывать несколько групп параметров, раделяя их данным флагом
Если соединение успешно прошло, то параметры для данного IP будут закешированны
-u, --cache-ttl <sec>
Время жизни значения в кеше, указывается в секундах
-q, --redirect <ip:port>
Перенаправить подключение на другой SOCKS5 прокси
Имеет смысл указывать после --auto, для перенаправление только заблокированных ресурсов
-s, --split <n[+s]>
Разбить запрос по указанному смещению
После числа можно добавить флаг: