mirror of
https://github.com/hufrea/byedpi.git
synced 2024-12-22 14:25:44 +00:00
Merge branch 'hufrea:main' into main
This commit is contained in:
commit
7f28255de7
30
README.md
30
README.md
@ -79,24 +79,34 @@ ciadpi --fake -1 --ttl 8
|
|||||||
-V, --pf <port[-portr]>
|
-V, --pf <port[-portr]>
|
||||||
Ограничитель по портам
|
Ограничитель по портам
|
||||||
|
|
||||||
-s, --split <n[+s]>
|
-R, --round <num[-numr]>
|
||||||
Разбить запрос по указанному смещению
|
К каким/какому запросу применять запутывание
|
||||||
После числа можно добавить флаг:
|
|
||||||
|
-s, --split <pos_t>
|
||||||
|
Разбить запрос по указанной позиции
|
||||||
|
Позиция имеет вид offset[:repeats:skip][+flag1[flag2]]
|
||||||
|
Флаги:
|
||||||
+s: добавить смещение SNI
|
+s: добавить смещение SNI
|
||||||
+h: добавить смещение Host
|
+h: добавить смещение Host
|
||||||
Можно указывать несколько раз, чтобы разбить запрос по нескольким позициям
|
+n: нулевое смещение
|
||||||
При указании отрицательного значения к нему прибавляется размер пакета
|
Дополнительные флаги:
|
||||||
|
+e: конец; +m: середина
|
||||||
|
Примеры:
|
||||||
|
0+sm - разбить запрос в середине SNI
|
||||||
|
1:3:5 - разбить по позициям 1, 6 и 11
|
||||||
|
Ключ можно указывать несколько раз, чтобы разбить запрос по нескольким позициям
|
||||||
|
Если offset отрицательный и не имеет флагов, то к нему прибавляется размер пакета
|
||||||
|
|
||||||
-d, --disorder <n[+s]>
|
-d, --disorder <pos_t>
|
||||||
Подобен --split, но части отправляются в обратном порядке
|
Подобен --split, но части отправляются в обратном порядке
|
||||||
|
|
||||||
-o, --oob <n[+s]>
|
-o, --oob <pos_t>
|
||||||
Подобен --split, но часть отсылается как OOB данные
|
Подобен --split, но часть отсылается как OOB данные
|
||||||
|
|
||||||
-q, --disoob <n[+s]>
|
-q, --disoob <pos_t>
|
||||||
Подобен --disorder, но часть отсылается как OOB данные
|
Подобен --disorder, но часть отсылается как OOB данные
|
||||||
|
|
||||||
-f, --fake <n[+s]>
|
-f, --fake <pos_t>
|
||||||
Подобен --disorder, только перед отправкой первого куска отправляется часть поддельного
|
Подобен --disorder, только перед отправкой первого куска отправляется часть поддельного
|
||||||
Количество байт отправляемого из фейка равно рамеру разбиваемой части
|
Количество байт отправляемого из фейка равно рамеру разбиваемой части
|
||||||
|
|
||||||
@ -136,7 +146,7 @@ ciadpi --fake -1 --ttl 8
|
|||||||
rmspace:
|
rmspace:
|
||||||
"Host: name" -> "Host:name\t"
|
"Host: name" -> "Host:name\t"
|
||||||
|
|
||||||
-r, --tlsrec <n[+s]>
|
-r, --tlsrec <pos_t>
|
||||||
Разделить ClientHello на отдельные записи по указанному смещению
|
Разделить ClientHello на отдельные записи по указанному смещению
|
||||||
Можно указывать несколько раз
|
Можно указывать несколько раз
|
||||||
|
|
||||||
|
17
conev.h
17
conev.h
@ -2,6 +2,7 @@
|
|||||||
#define CONEV_H
|
#define CONEV_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
#define NOEPOLL
|
#define NOEPOLL
|
||||||
@ -37,9 +38,8 @@ enum eid {
|
|||||||
EV_CONNECT,
|
EV_CONNECT,
|
||||||
EV_IGNORE,
|
EV_IGNORE,
|
||||||
EV_TUNNEL,
|
EV_TUNNEL,
|
||||||
EV_PRE_TUNNEL,
|
|
||||||
EV_UDP_TUNNEL,
|
EV_UDP_TUNNEL,
|
||||||
EV_DESYNC
|
EV_FIRST_TUNNEL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLAG_S4 1
|
#define FLAG_S4 1
|
||||||
@ -53,15 +53,14 @@ char *eid_name[] = {
|
|||||||
"EV_CONNECT",
|
"EV_CONNECT",
|
||||||
"EV_IGNORE",
|
"EV_IGNORE",
|
||||||
"EV_TUNNEL",
|
"EV_TUNNEL",
|
||||||
"EV_PRE_TUNNEL",
|
|
||||||
"EV_UDP_TUNNEL",
|
"EV_UDP_TUNNEL",
|
||||||
"EV_DESYNC"
|
"EV_FIRST_TUNNEL"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct buffer {
|
struct buffer {
|
||||||
ssize_t size;
|
size_t size;
|
||||||
int offset;
|
unsigned int offset;
|
||||||
char *data;
|
char *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,11 +77,11 @@ struct eval {
|
|||||||
struct sockaddr_in6 in6;
|
struct sockaddr_in6 in6;
|
||||||
};
|
};
|
||||||
ssize_t recv_count;
|
ssize_t recv_count;
|
||||||
|
ssize_t round_sent;
|
||||||
unsigned int round_count;
|
unsigned int round_count;
|
||||||
char last_round;
|
|
||||||
int attempt;
|
int attempt;
|
||||||
char cache;
|
bool cache;
|
||||||
char mark; //
|
bool mark; //
|
||||||
};
|
};
|
||||||
|
|
||||||
struct poolhd {
|
struct poolhd {
|
||||||
|
41
desync.c
41
desync.c
@ -434,19 +434,19 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize,
|
|||||||
char *host = 0;
|
char *host = 0;
|
||||||
int len = 0, type = 0, host_pos = 0;
|
int len = 0, type = 0, host_pos = 0;
|
||||||
|
|
||||||
// parse packet
|
if (offset == 0) {
|
||||||
if ((len = parse_tls(buffer, n, &host))) {
|
if ((len = parse_tls(buffer, n, &host))) {
|
||||||
type = IS_HTTPS;
|
type = IS_HTTPS;
|
||||||
|
}
|
||||||
|
else if ((len = parse_http(buffer, n, &host, 0))) {
|
||||||
|
type = IS_HTTP;
|
||||||
|
}
|
||||||
|
if (len && host) {
|
||||||
|
LOG(LOG_S, "host: %.*s (%zd)\n",
|
||||||
|
len, host, host - buffer);
|
||||||
|
host_pos = host - buffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ((len = parse_http(buffer, n, &host, 0))) {
|
|
||||||
type = IS_HTTP;
|
|
||||||
}
|
|
||||||
if (len && host) {
|
|
||||||
LOG(LOG_S, "host: %.*s (%zd)\n",
|
|
||||||
len, host, host - buffer);
|
|
||||||
host_pos = host - buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// modify packet
|
// modify packet
|
||||||
if (type == IS_HTTP && dp.mod_http) {
|
if (type == IS_HTTP && dp.mod_http) {
|
||||||
LOG(LOG_S, "modify HTTP: n=%zd\n", n);
|
LOG(LOG_S, "modify HTTP: n=%zd\n", n);
|
||||||
@ -469,7 +469,7 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize,
|
|||||||
pos += gen_offset(part.pos,
|
pos += gen_offset(part.pos,
|
||||||
part.flag, n - pos - 5, lp, type, host_pos - 5, len);
|
part.flag, n - pos - 5, lp, type, host_pos - 5, len);
|
||||||
|
|
||||||
pos += part.s * (part.r - r);
|
pos += (long)part.s * (part.r - r);
|
||||||
if (pos < lp) {
|
if (pos < lp) {
|
||||||
LOG(LOG_E, "tlsrec cancel: %ld < %ld\n", pos, lp);
|
LOG(LOG_E, "tlsrec cancel: %ld < %ld\n", pos, lp);
|
||||||
break;
|
break;
|
||||||
@ -484,13 +484,12 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize,
|
|||||||
lp = pos + 5;
|
lp = pos + 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// desync
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (dp.drop_sack && drop_sack(sfd)) {
|
if (!offset && dp.drop_sack && drop_sack(sfd)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
long lp = offset;
|
long lp = 0;
|
||||||
struct part part;
|
struct part part;
|
||||||
int i = 0, r = 0;
|
int i = 0, r = 0;
|
||||||
|
|
||||||
@ -502,17 +501,17 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize,
|
|||||||
long pos = gen_offset(part.pos,
|
long pos = gen_offset(part.pos,
|
||||||
part.flag, n, lp, type, host_pos, len);
|
part.flag, n, lp, type, host_pos, len);
|
||||||
|
|
||||||
pos += part.s * (part.r - r);
|
pos += (long)part.s * (part.r - r);
|
||||||
|
|
||||||
// after EAGAIN
|
if (!(part.flag & OFFSET_START) && offset && pos <= offset) {
|
||||||
if (offset && pos <= offset) {
|
LOG(LOG_S, "offset: %zd, skip\n", offset);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (pos < 0 || pos > n || pos < lp) {
|
if (pos < 0 || pos > n || pos < lp) {
|
||||||
LOG(LOG_E, "split cancel: pos=%ld-%ld, n=%zd\n", lp, pos, n);
|
LOG(LOG_E, "split cancel: pos=%ld-%ld, n=%zd\n", lp, pos, n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// send part
|
|
||||||
ssize_t s = 0;
|
ssize_t s = 0;
|
||||||
switch (part.m) {
|
switch (part.m) {
|
||||||
#ifdef FAKE_SUPPORT
|
#ifdef FAKE_SUPPORT
|
||||||
|
527
extend.c
527
extend.c
@ -26,7 +26,7 @@
|
|||||||
#define KEY_SIZE sizeof(struct sockaddr_ina)
|
#define KEY_SIZE sizeof(struct sockaddr_ina)
|
||||||
|
|
||||||
|
|
||||||
int set_timeout(int fd, unsigned int s)
|
static int set_timeout(int fd, unsigned int s)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (setsockopt(fd, IPPROTO_TCP,
|
if (setsockopt(fd, IPPROTO_TCP,
|
||||||
@ -72,50 +72,48 @@ static ssize_t serialize_addr(const struct sockaddr_ina *dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int mode_add_get(struct sockaddr_ina *dst, int m)
|
static int cache_get(struct sockaddr_ina *dst)
|
||||||
{
|
{
|
||||||
// m < 0: get, m > 0: set, m == 0: delete
|
uint8_t key[KEY_SIZE] = { 0 };
|
||||||
assert(m >= -1 && m < params.dp_count);
|
int len = serialize_addr(dst, key, sizeof(key));
|
||||||
|
|
||||||
time_t t = 0;
|
struct elem *val = mem_get(params.mempool, (char *)key, len);
|
||||||
struct elem *val = 0;
|
if (!val) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
time_t t = time(0);
|
||||||
|
if (t > val->time + params.cache_ttl) {
|
||||||
|
LOG(LOG_S, "time=%jd, now=%jd, ignore\n", (intmax_t)val->time, (intmax_t)t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return val->m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cache_add(struct sockaddr_ina *dst, int m)
|
||||||
|
{
|
||||||
|
assert(m >= 0 && m < params.dp_count);
|
||||||
|
|
||||||
uint8_t key[KEY_SIZE] = { 0 };
|
uint8_t key[KEY_SIZE] = { 0 };
|
||||||
int len = serialize_addr(dst, key, sizeof(key));
|
int len = serialize_addr(dst, key, sizeof(key));
|
||||||
assert(len > 0);
|
|
||||||
|
|
||||||
if (m < 0) {
|
|
||||||
val = mem_get(params.mempool, (char *)key, len);
|
|
||||||
if (!val) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
time(&t);
|
|
||||||
if (t > val->time + params.cache_ttl) {
|
|
||||||
LOG(LOG_S, "time=%jd, now=%jd, ignore\n", (intmax_t)val->time, (intmax_t)t);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return val->m;
|
|
||||||
}
|
|
||||||
INIT_ADDR_STR((*dst));
|
INIT_ADDR_STR((*dst));
|
||||||
|
|
||||||
if (m == 0) {
|
if (m == 0) {
|
||||||
LOG(LOG_S, "delete ip: %s\n", ADDR_STR);
|
LOG(LOG_S, "delete ip: %s\n", ADDR_STR);
|
||||||
mem_delete(params.mempool, (char *)key, len);
|
mem_delete(params.mempool, (char *)key, len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m);
|
||||||
LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m);
|
time_t t = time(0);
|
||||||
time(&t);
|
|
||||||
|
|
||||||
val = mem_add(params.mempool, (char *)key, len);
|
struct elem *val = mem_add(params.mempool, (char *)key, len);
|
||||||
if (!val) {
|
if (!val) {
|
||||||
uniperror("mem_add");
|
uniperror("mem_add");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
val->m = m;
|
|
||||||
val->time = t;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
val->m = m;
|
||||||
|
val->time = t;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,7 +127,7 @@ static inline bool check_port(uint16_t *p, struct sockaddr_in6 *dst)
|
|||||||
int connect_hook(struct poolhd *pool, struct eval *val,
|
int connect_hook(struct poolhd *pool, struct eval *val,
|
||||||
struct sockaddr_ina *dst, int next)
|
struct sockaddr_ina *dst, int next)
|
||||||
{
|
{
|
||||||
int m = mode_add_get(dst, -1);
|
int m = cache_get(dst);
|
||||||
val->cache = (m == 0);
|
val->cache = (m == 0);
|
||||||
val->attempt = m < 0 ? 0 : m;
|
val->attempt = m < 0 ? 0 : m;
|
||||||
|
|
||||||
@ -151,31 +149,34 @@ int socket_mod(int fd, struct sockaddr *dst)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int reconnect(struct poolhd *pool, struct eval *val, int m)
|
static int reconnect(struct poolhd *pool, struct eval *val, int m)
|
||||||
{
|
{
|
||||||
|
assert(val->flag == FLAG_CONN);
|
||||||
|
|
||||||
struct eval *client = val->pair;
|
struct eval *client = val->pair;
|
||||||
|
|
||||||
if (create_conn(pool, client,
|
if (create_conn(pool, client,
|
||||||
(struct sockaddr_ina *)&val->in6, EV_DESYNC)) {
|
(struct sockaddr_ina *)&val->in6, EV_FIRST_TUNNEL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->pair = 0;
|
val->pair = 0;
|
||||||
del_event(pool, val);
|
del_event(pool, val);
|
||||||
|
|
||||||
client->type = EV_IGNORE;
|
//client->type = EV_IGNORE;
|
||||||
client->attempt = m;
|
client->attempt = m;
|
||||||
client->cache = 1;
|
client->cache = 1;
|
||||||
client->buff.offset = 0;
|
client->buff.offset = 0;
|
||||||
|
client->round_sent = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool check_host(struct mphdr *hosts, struct eval *val)
|
static bool check_host(struct mphdr *hosts, char *buffer, ssize_t n)
|
||||||
{
|
{
|
||||||
char *host = 0;
|
char *host = 0;
|
||||||
int len;
|
int len;
|
||||||
if (!(len = parse_tls(val->buff.data, val->buff.size, &host))) {
|
if (!(len = parse_tls(buffer, n, &host))) {
|
||||||
len = parse_http(val->buff.data, val->buff.size, &host, 0);
|
len = parse_http(buffer, n, &host, 0);
|
||||||
}
|
}
|
||||||
assert(len == 0 || host != 0);
|
assert(len == 0 || host != 0);
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
@ -194,111 +195,90 @@ bool check_host(struct mphdr *hosts, struct eval *val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool check_proto_tcp(int proto, struct eval *val)
|
static bool check_proto_tcp(int proto, char *buffer, ssize_t n)
|
||||||
{
|
{
|
||||||
if (proto & IS_TCP) {
|
if (proto & IS_TCP) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((proto & IS_HTTP) &&
|
else if ((proto & IS_HTTP) &&
|
||||||
is_http(val->buff.data, val->buff.size)) {
|
is_http(buffer, n)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if ((proto & IS_HTTPS) &&
|
else if ((proto & IS_HTTPS) &&
|
||||||
is_tls_chello(val->buff.data, val->buff.size)) {
|
is_tls_chello(buffer, n)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int on_torst(struct poolhd *pool, struct eval *val)
|
static bool check_round(int *nr, int r)
|
||||||
{
|
{
|
||||||
int m = val->pair->attempt + 1;
|
return (!nr[1] && r <= 1) || (r >= nr[0] && r <= nr[1]);
|
||||||
|
|
||||||
bool can_reconn = (
|
|
||||||
val->pair->buff.data && !val->recv_count
|
|
||||||
);
|
|
||||||
if (can_reconn || params.auto_level >= 1) {
|
|
||||||
for (; m < params.dp_count; m++) {
|
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
|
||||||
if (!dp->detect) {
|
|
||||||
m = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dp->detect & DETECT_TORST) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m == 0) {
|
|
||||||
}
|
|
||||||
else if (m >= params.dp_count) {
|
|
||||||
if (m > 1) mode_add_get(
|
|
||||||
(struct sockaddr_ina *)&val->in6, 0);
|
|
||||||
}
|
|
||||||
else if (can_reconn) {
|
|
||||||
return reconnect(pool, val, m);
|
|
||||||
}
|
|
||||||
else mode_add_get(
|
|
||||||
(struct sockaddr_ina *)&val->in6, m);
|
|
||||||
}
|
|
||||||
struct linger l = { .l_onoff = 1 };
|
|
||||||
if (setsockopt(val->pair->fd, SOL_SOCKET,
|
|
||||||
SO_LINGER, (char *)&l, sizeof(l)) < 0) {
|
|
||||||
uniperror("setsockopt SO_LINGER");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int on_fin(struct poolhd *pool, struct eval *val)
|
static int on_trigger(int type, struct poolhd *pool, struct eval *val)
|
||||||
{
|
{
|
||||||
int m = val->pair->attempt + 1;
|
int m = val->pair->attempt + 1;
|
||||||
|
|
||||||
bool can_reconn = (
|
bool can_reconn = (
|
||||||
val->pair->buff.data && !val->recv_count
|
val->pair->buff.data && !val->recv_count
|
||||||
|
&& params.auto_level > AUTO_NOBUFF
|
||||||
);
|
);
|
||||||
if (!can_reconn && params.auto_level < 1) {
|
if (!can_reconn && params.auto_level <= AUTO_NOSAVE) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
bool ssl_err = 0;
|
|
||||||
|
|
||||||
if (can_reconn) {
|
|
||||||
char *req = val->pair->buff.data;
|
|
||||||
ssize_t qn = val->pair->buff.size;
|
|
||||||
|
|
||||||
ssl_err = is_tls_chello(req, qn);
|
|
||||||
}
|
|
||||||
else if (val->mark && val->round_count <= 1) {
|
|
||||||
ssl_err = 1;
|
|
||||||
}
|
|
||||||
if (!ssl_err) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (; m < params.dp_count; m++) {
|
for (; m < params.dp_count; m++) {
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
if (!dp->detect) {
|
if (!dp->detect) {
|
||||||
return -1;
|
break;
|
||||||
}
|
}
|
||||||
if (dp->detect & DETECT_TLS_ERR) {
|
if (!(dp->detect & type)) {
|
||||||
if (can_reconn)
|
continue;
|
||||||
return reconnect(pool, val, m);
|
|
||||||
else {
|
|
||||||
mode_add_get(
|
|
||||||
(struct sockaddr_ina *)&val->in6, m);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (can_reconn) {
|
||||||
|
return reconnect(pool, val, m);
|
||||||
|
}
|
||||||
|
cache_add(
|
||||||
|
(struct sockaddr_ina *)&val->in6, m);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (m > 1) { // delete
|
if (m >= params.dp_count && m > 1) {
|
||||||
mode_add_get(
|
cache_add(
|
||||||
(struct sockaddr_ina *)&val->in6, 0);
|
(struct sockaddr_ina *)&val->in6, 0);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int on_response(struct poolhd *pool, struct eval *val,
|
static int on_torst(struct poolhd *pool, struct eval *val)
|
||||||
|
{
|
||||||
|
if (on_trigger(DETECT_TORST, pool, val) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
struct linger l = { .l_onoff = 1 };
|
||||||
|
if (setsockopt(val->pair->fd, SOL_SOCKET,
|
||||||
|
SO_LINGER, (char *)&l, sizeof(l)) < 0) {
|
||||||
|
uniperror("setsockopt SO_LINGER");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int on_fin(struct poolhd *pool, struct eval *val)
|
||||||
|
{
|
||||||
|
if (!(val->pair->mark && val->round_count <= 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (on_trigger(DETECT_TLS_ERR, pool, val) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int on_response(struct poolhd *pool, struct eval *val,
|
||||||
char *resp, ssize_t sn)
|
char *resp, ssize_t sn)
|
||||||
{
|
{
|
||||||
int m = val->pair->attempt + 1;
|
int m = val->pair->attempt + 1;
|
||||||
@ -328,177 +308,240 @@ int on_response(struct poolhd *pool, struct eval *val,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void to_tunnel(struct eval *client)
|
static inline void free_first_req(struct eval *client)
|
||||||
{
|
{
|
||||||
client->pair->type = EV_TUNNEL;
|
|
||||||
client->type = EV_TUNNEL;
|
client->type = EV_TUNNEL;
|
||||||
|
client->pair->type = EV_TUNNEL;
|
||||||
|
|
||||||
assert(client->buff.data);
|
|
||||||
free(client->buff.data);
|
free(client->buff.data);
|
||||||
client->buff.data = 0;
|
memset(&client->buff, 0, sizeof(client->buff));
|
||||||
client->buff.size = 0;
|
|
||||||
client->buff.offset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
static int setup_conn(struct eval *client, char *buffer, ssize_t n)
|
||||||
char *buffer, size_t bfsize, int out)
|
{
|
||||||
|
int m = client->attempt;
|
||||||
|
|
||||||
|
if (!m) for (; m < params.dp_count; m++) {
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
if (!dp->detect &&
|
||||||
|
(!dp->pf[0] || check_port(dp->pf, &client->pair->in6)) &&
|
||||||
|
(!dp->proto || check_proto_tcp(dp->proto, buffer, n)) &&
|
||||||
|
(!dp->hosts || check_host(dp->hosts, buffer, n))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m >= params.dp_count) {
|
||||||
|
LOG(LOG_E, "drop connection (m=%d)\n", m);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (params.auto_level > AUTO_NOBUFF && params.dp_count > 1) {
|
||||||
|
client->mark = is_tls_chello(buffer, n);
|
||||||
|
}
|
||||||
|
client->attempt = m;
|
||||||
|
|
||||||
|
if (params.timeout
|
||||||
|
&& set_timeout(client->pair->fd, params.timeout)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cancel_setup(struct eval *remote)
|
||||||
|
{
|
||||||
|
if (params.timeout && params.auto_level <= AUTO_NOSAVE &&
|
||||||
|
set_timeout(remote->fd, 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (post_desync(remote->fd, remote->pair->attempt)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int send_saved_req(struct poolhd *pool,
|
||||||
|
struct eval *client, char *buffer, ssize_t bfsize)
|
||||||
|
{
|
||||||
|
ssize_t offset = client->buff.offset;
|
||||||
|
ssize_t n = client->buff.size - offset;
|
||||||
|
assert(bfsize >= n);
|
||||||
|
memcpy(buffer, client->buff.data + offset, n);
|
||||||
|
|
||||||
|
ssize_t sn = tcp_send_hook(client->pair, buffer, bfsize, n);
|
||||||
|
if (sn < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
client->buff.offset += sn;
|
||||||
|
if (sn < n) {
|
||||||
|
if (mod_etype(pool, client->pair, POLLOUT) ||
|
||||||
|
mod_etype(pool, client, 0)) {
|
||||||
|
uniperror("mod_etype");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int on_first_tunnel(struct poolhd *pool,
|
||||||
|
struct eval *val, char *buffer, ssize_t bfsize, int etype)
|
||||||
|
{
|
||||||
|
if ((etype & POLLOUT) && val->flag == FLAG_CONN) {
|
||||||
|
if (mod_etype(pool, val, POLLIN) ||
|
||||||
|
mod_etype(pool, val->pair, POLLIN)) {
|
||||||
|
uniperror("mod_etype");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return send_saved_req(pool, val->pair, buffer, bfsize);
|
||||||
|
}
|
||||||
|
ssize_t n = tcp_recv_hook(pool, val, buffer, bfsize);
|
||||||
|
if (n < 1) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
if (val->flag != FLAG_CONN) {
|
||||||
|
val->buff.size += n;
|
||||||
|
|
||||||
|
if (val->buff.size >= bfsize) {
|
||||||
|
free_first_req(val);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val->buff.data = realloc(val->buff.data, val->buff.size);
|
||||||
|
|
||||||
|
if (val->buff.data == 0) {
|
||||||
|
uniperror("realloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(val->buff.data + val->buff.size - n, buffer, n);
|
||||||
|
return send_saved_req(pool, val, buffer, bfsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (on_response(pool, val, buffer, n) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free_first_req(val->pair);
|
||||||
|
int m = val->pair->attempt;
|
||||||
|
|
||||||
|
if (val->pair->cache &&
|
||||||
|
cache_add((struct sockaddr_ina *)&val->in6, m) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tcp_send_hook(val->pair, buffer, bfsize, n) < n) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t tcp_send_hook(struct eval *remote,
|
||||||
|
char *buffer, size_t bfsize, ssize_t n)
|
||||||
|
{
|
||||||
|
ssize_t sn = -1;
|
||||||
|
int skip = remote->flag != FLAG_CONN;
|
||||||
|
|
||||||
|
if (!skip) {
|
||||||
|
struct eval *client = remote->pair;
|
||||||
|
|
||||||
|
if (client->recv_count == n
|
||||||
|
&& setup_conn(client, buffer, n) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int m = client->attempt, r = client->round_count;
|
||||||
|
if (!check_round(params.dp[m].rounds, r)) {
|
||||||
|
skip = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((m ? LOG_S : LOG_L), "desync TCP, m=%d, r=%d\n", m, r);
|
||||||
|
|
||||||
|
ssize_t offset = remote->pair->round_sent;
|
||||||
|
if (!offset && remote->round_count) offset = -1;
|
||||||
|
|
||||||
|
sn = desync(remote->fd, buffer, bfsize, n,
|
||||||
|
offset, (struct sockaddr *)&remote->in6, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skip) {
|
||||||
|
sn = send(remote->fd, buffer, n, 0);
|
||||||
|
if (sn < 0 && get_e() == EAGAIN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remote->pair->round_sent += sn;
|
||||||
|
return sn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t tcp_recv_hook(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize)
|
||||||
{
|
{
|
||||||
assert(!out);
|
|
||||||
ssize_t n = recv(val->fd, buffer, bfsize, 0);
|
ssize_t n = recv(val->fd, buffer, bfsize, 0);
|
||||||
if (n < 1) {
|
if (n < 1) {
|
||||||
if (!n) {
|
if (!n) {
|
||||||
|
if (val->flag != FLAG_CONN) {
|
||||||
|
val = val->pair;
|
||||||
|
}
|
||||||
return on_fin(pool, val);
|
return on_fin(pool, val);
|
||||||
}
|
}
|
||||||
|
if (get_e() == EAGAIN) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
uniperror("recv");
|
uniperror("recv");
|
||||||
switch (get_e()) {
|
switch (get_e()) {
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return on_torst(pool, val);
|
if (val->flag == FLAG_CONN)
|
||||||
|
return on_torst(pool, val);
|
||||||
|
else
|
||||||
|
return on_fin(pool, val->pair);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
if (on_response(pool, val, buffer, n) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
val->recv_count += n;
|
val->recv_count += n;
|
||||||
val->round_count = 1;
|
if (val->round_sent == 0) {
|
||||||
val->last_round = 1;
|
val->round_count++;
|
||||||
struct eval *pair = val->pair;
|
val->pair->round_sent = 0;
|
||||||
|
|
||||||
ssize_t sn = send(pair->fd, buffer, n, 0);
|
|
||||||
if (n != sn) {
|
|
||||||
uniperror("send");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (params.auto_level > 0 && params.dp_count > 1) {
|
if (val->flag == FLAG_CONN && !val->round_sent) {
|
||||||
val->mark = is_tls_chello(pair->buff.data, pair->buff.size);
|
int *nr = params.dp[val->pair->attempt].rounds;
|
||||||
}
|
|
||||||
to_tunnel(pair);
|
if (check_round(nr, val->round_count)
|
||||||
|
&& !check_round(nr, val->round_count + 1)
|
||||||
if (params.timeout && params.auto_level < 1 &&
|
&& cancel_setup(val)) {
|
||||||
set_timeout(val->fd, 0)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int m = pair->attempt;
|
|
||||||
|
|
||||||
if (post_desync(val->fd, m)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pair->cache) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mode_add_get((struct sockaddr_ina *)&val->in6, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int on_desync_again(struct poolhd *pool,
|
|
||||||
struct eval *val, char *buffer, size_t bfsize)
|
|
||||||
{
|
|
||||||
if (val->flag == FLAG_CONN) {
|
|
||||||
if (mod_etype(pool, val, POLLIN) ||
|
|
||||||
mod_etype(pool, val->pair, POLLIN)) {
|
|
||||||
uniperror("mod_etype");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val = val->pair;
|
|
||||||
}
|
}
|
||||||
int m = val->attempt;
|
return n;
|
||||||
LOG((m ? LOG_S : LOG_L), "desync params index: %d\n", m);
|
|
||||||
|
|
||||||
ssize_t n = val->buff.size;
|
|
||||||
assert(n > 0 && n <= params.bfsize);
|
|
||||||
memcpy(buffer, val->buff.data, n);
|
|
||||||
|
|
||||||
if (params.timeout &&
|
|
||||||
set_timeout(val->pair->fd, params.timeout)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ssize_t sn = desync(val->pair->fd, buffer, bfsize, n,
|
|
||||||
val->buff.offset, (struct sockaddr *)&val->pair->in6, m);
|
|
||||||
if (sn < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->buff.offset += sn;
|
|
||||||
if (sn < n) {
|
|
||||||
if (mod_etype(pool, val->pair, POLLOUT)) {
|
|
||||||
uniperror("mod_etype");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->pair->type = EV_DESYNC;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
val->pair->type = EV_PRE_TUNNEL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int on_desync(struct poolhd *pool, struct eval *val,
|
|
||||||
char *buffer, size_t bfsize, int out)
|
|
||||||
{
|
|
||||||
if (out) {
|
|
||||||
return on_desync_again(pool, val, buffer, bfsize);
|
|
||||||
}
|
|
||||||
if (val->buff.size == bfsize) {
|
|
||||||
to_tunnel(val);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ssize_t n = recv(val->fd, buffer, bfsize - val->buff.size, 0);
|
|
||||||
if (n <= 0) {
|
|
||||||
if (n) uniperror("recv data");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->buff.size += n;
|
|
||||||
val->recv_count += n;
|
|
||||||
val->round_count = 1;
|
|
||||||
|
|
||||||
val->buff.data = realloc(val->buff.data, val->buff.size);
|
|
||||||
if (val->buff.data == 0) {
|
|
||||||
uniperror("realloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(val->buff.data + val->buff.size - n, buffer, n);
|
|
||||||
|
|
||||||
int m = val->attempt;
|
|
||||||
if (!m) for (; m < params.dp_count; m++) {
|
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
|
||||||
if (!dp->detect &&
|
|
||||||
(!dp->pf[0] || check_port(dp->pf, &val->pair->in6)) &&
|
|
||||||
(!dp->proto || check_proto_tcp(dp->proto, val)) &&
|
|
||||||
(!dp->hosts || check_host(dp->hosts, val))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m >= params.dp_count) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->attempt = m;
|
|
||||||
|
|
||||||
return on_desync_again(pool, val, buffer, bfsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t udp_hook(struct eval *val,
|
ssize_t udp_hook(struct eval *val,
|
||||||
char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst)
|
char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst)
|
||||||
{
|
{
|
||||||
if (val->recv_count) {
|
struct eval *pair = val->pair->pair;
|
||||||
|
|
||||||
|
int m = pair->attempt, r = pair->round_count;
|
||||||
|
if (!m) {
|
||||||
|
for (; m < params.dp_count; m++) {
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
if (!dp->detect &&
|
||||||
|
(!dp->proto || (dp->proto & IS_UDP)) &&
|
||||||
|
(!dp->pf[0] || check_port(dp->pf, &dst->in6))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m >= params.dp_count) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pair->attempt = m;
|
||||||
|
}
|
||||||
|
if (!check_round(params.dp[m].rounds, r)) {
|
||||||
return send(val->fd, buffer, n, 0);
|
return send(val->fd, buffer, n, 0);
|
||||||
}
|
}
|
||||||
int m = val->attempt;
|
LOG(LOG_S, "desync UDP, m=%d, r=%d\n", m, r);
|
||||||
if (!m) for (; m < params.dp_count; m++) {
|
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
|
||||||
if (!dp->detect &&
|
|
||||||
(!dp->proto || (dp->proto & IS_UDP)) &&
|
|
||||||
(!dp->pf[0] || check_port(dp->pf, &dst->in6))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m >= params.dp_count) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return desync_udp(val->fd, buffer, bfsize, n, &dst->sa, m);
|
return desync_udp(val->fd, buffer, bfsize, n, &dst->sa, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
extend.h
19
extend.h
@ -10,19 +10,18 @@ int socket_mod(int fd, struct sockaddr *dst);
|
|||||||
int connect_hook(struct poolhd *pool, struct eval *val,
|
int connect_hook(struct poolhd *pool, struct eval *val,
|
||||||
struct sockaddr_ina *dst, int next);
|
struct sockaddr_ina *dst, int next);
|
||||||
|
|
||||||
int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
ssize_t tcp_send_hook(struct eval *val,
|
||||||
char *buffer, size_t bfsize, int out);
|
char *buffer, size_t bfsize, ssize_t n);
|
||||||
|
|
||||||
int on_desync(struct poolhd *pool, struct eval *val,
|
ssize_t tcp_recv_hook(struct poolhd *pool, struct eval *val,
|
||||||
char *buffer, size_t bfsize, int out);
|
char *buffer, size_t bfsize);
|
||||||
|
|
||||||
ssize_t udp_hook(struct eval *val,
|
ssize_t udp_hook(struct eval *val,
|
||||||
char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst);
|
char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst);
|
||||||
|
|
||||||
int on_torst(struct poolhd *pool, struct eval *val);
|
int on_first_tunnel(struct poolhd *pool,
|
||||||
|
struct eval *val, char *buffer, ssize_t bfsize, int etype);
|
||||||
int on_fin(struct poolhd *pool, struct eval *val);
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int protect(int conn_fd, const char *path);
|
int protect(int conn_fd, const char *path);
|
||||||
#else
|
#else
|
||||||
|
39
main.c
39
main.c
@ -23,7 +23,7 @@
|
|||||||
#define close(fd) closesocket(fd)
|
#define close(fd) closesocket(fd)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VERSION "14.1"
|
#define VERSION "15"
|
||||||
|
|
||||||
char ip_option[1] = "\0";
|
char ip_option[1] = "\0";
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ struct params params = {
|
|||||||
.sin6_family = AF_INET
|
.sin6_family = AF_INET
|
||||||
},
|
},
|
||||||
.debug = 0,
|
.debug = 0,
|
||||||
.auto_level = 0
|
.auto_level = AUTO_NOBUFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -86,9 +86,10 @@ const char help_text[] = {
|
|||||||
" -K, --proto <t,h,u> Protocol whitelist: tls,http,udp\n"
|
" -K, --proto <t,h,u> Protocol whitelist: tls,http,udp\n"
|
||||||
" -H, --hosts <file|:str> Hosts whitelist, filename or :string\n"
|
" -H, --hosts <file|:str> Hosts whitelist, filename or :string\n"
|
||||||
" -V, --pf <port[-portr]> Ports range whitelist\n"
|
" -V, --pf <port[-portr]> Ports range whitelist\n"
|
||||||
|
" -R, --round <num[-numr]> Number of request to which desync will be applied\n"
|
||||||
" -s, --split <pos_t> Position format: offset[:repeats:skip][+flag1[flag2]]\n"
|
" -s, --split <pos_t> Position format: offset[:repeats:skip][+flag1[flag2]]\n"
|
||||||
" Flags: +s - SNI offset, +h - HTTP host offset\n"
|
" Flags: +s - SNI offset, +h - HTTP host offset, +n - null\n"
|
||||||
" Additional flags: +e - end, +m - middle, +r - random\n"
|
" Additional flags: +e - end, +m - middle\n"
|
||||||
" -d, --disorder <pos_t> Split and send reverse order\n"
|
" -d, --disorder <pos_t> Split and send reverse order\n"
|
||||||
" -o, --oob <pos_t> Split and send as OOB data\n"
|
" -o, --oob <pos_t> Split and send as OOB data\n"
|
||||||
" -q, --disoob <pos_t> Split and send reverse order as OOB data\n"
|
" -q, --disoob <pos_t> Split and send reverse order as OOB data\n"
|
||||||
@ -141,6 +142,7 @@ const struct option options[] = {
|
|||||||
{"proto", 1, 0, 'K'},
|
{"proto", 1, 0, 'K'},
|
||||||
{"hosts", 1, 0, 'H'},
|
{"hosts", 1, 0, 'H'},
|
||||||
{"pf", 1, 0, 'V'},
|
{"pf", 1, 0, 'V'},
|
||||||
|
{"round", 1, 0, 'R'},
|
||||||
{"split", 1, 0, 's'},
|
{"split", 1, 0, 's'},
|
||||||
{"disorder", 1, 0, 'd'},
|
{"disorder", 1, 0, 'd'},
|
||||||
{"oob", 1, 0, 'o'},
|
{"oob", 1, 0, 'o'},
|
||||||
@ -400,9 +402,6 @@ int parse_offset(struct part *part, const char *str)
|
|||||||
case 'h':
|
case 'h':
|
||||||
part->flag = OFFSET_HOST;
|
part->flag = OFFSET_HOST;
|
||||||
break;
|
break;
|
||||||
case 'e': //
|
|
||||||
part->flag = OFFSET_END;
|
|
||||||
break;
|
|
||||||
case 'n':
|
case 'n':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -415,10 +414,11 @@ int parse_offset(struct part *part, const char *str)
|
|||||||
case 'm':
|
case 'm':
|
||||||
part->flag |= OFFSET_MID;
|
part->flag |= OFFSET_MID;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r': //
|
||||||
part->flag |= OFFSET_RAND;
|
part->flag |= OFFSET_RAND;
|
||||||
break;
|
break;
|
||||||
case 's':;
|
case 's': //
|
||||||
|
part->flag |= OFFSET_START;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
part->pos = val;
|
part->pos = val;
|
||||||
@ -648,6 +648,9 @@ int main(int argc, char **argv)
|
|||||||
end = strchr(end, ',');
|
end = strchr(end, ',');
|
||||||
if (end) end++;
|
if (end) end++;
|
||||||
}
|
}
|
||||||
|
if (dp->detect && params.auto_level == AUTO_NOBUFF) {
|
||||||
|
params.auto_level = AUTO_NOSAVE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
@ -866,6 +869,24 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
val = strtol(optarg, &end, 0);
|
||||||
|
if (val <= 0 || val > INT_MAX)
|
||||||
|
invalid = 1;
|
||||||
|
else {
|
||||||
|
dp->rounds[0] = val;
|
||||||
|
if (*end == '-') {
|
||||||
|
val = strtol(end + 1, &end, 0);
|
||||||
|
if (val <= 0 || val > INT_MAX)
|
||||||
|
invalid = 1;
|
||||||
|
}
|
||||||
|
if (*end)
|
||||||
|
invalid = 1;
|
||||||
|
else
|
||||||
|
dp->rounds[1] = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
val = strtol(optarg, &end, 0);
|
val = strtol(optarg, &end, 0);
|
||||||
if (val <= 0 || val > 255 || *end)
|
if (val <= 0 || val > 255 || *end)
|
||||||
|
5
params.h
5
params.h
@ -26,11 +26,15 @@
|
|||||||
#define OFFSET_RAND 4
|
#define OFFSET_RAND 4
|
||||||
#define OFFSET_SNI 8
|
#define OFFSET_SNI 8
|
||||||
#define OFFSET_HOST 16
|
#define OFFSET_HOST 16
|
||||||
|
#define OFFSET_START 32
|
||||||
|
|
||||||
#define DETECT_HTTP_LOCAT 1
|
#define DETECT_HTTP_LOCAT 1
|
||||||
#define DETECT_TLS_ERR 2
|
#define DETECT_TLS_ERR 2
|
||||||
#define DETECT_TORST 8
|
#define DETECT_TORST 8
|
||||||
|
|
||||||
|
#define AUTO_NOBUFF -1
|
||||||
|
#define AUTO_NOSAVE 0
|
||||||
|
|
||||||
enum demode {
|
enum demode {
|
||||||
DESYNC_NONE,
|
DESYNC_NONE,
|
||||||
DESYNC_SPLIT,
|
DESYNC_SPLIT,
|
||||||
@ -85,6 +89,7 @@ struct desync_params {
|
|||||||
int detect;
|
int detect;
|
||||||
struct mphdr *hosts;
|
struct mphdr *hosts;
|
||||||
uint16_t pf[2];
|
uint16_t pf[2];
|
||||||
|
int rounds[2];
|
||||||
|
|
||||||
char *file_ptr;
|
char *file_ptr;
|
||||||
ssize_t file_size;
|
ssize_t file_size;
|
||||||
|
172
proxy.c
172
proxy.c
@ -334,30 +334,27 @@ int s5_set_addr(char *buffer, size_t n,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int create_conn(struct poolhd *pool,
|
static int remote_sock(struct sockaddr_ina *dst, int type)
|
||||||
struct eval *val, struct sockaddr_ina *dst, int next)
|
|
||||||
{
|
{
|
||||||
struct sockaddr_ina addr = *dst;
|
|
||||||
|
|
||||||
if (params.baddr.sin6_family == AF_INET6) {
|
if (params.baddr.sin6_family == AF_INET6) {
|
||||||
map_fix(&addr, 6);
|
map_fix(dst, 6);
|
||||||
} else {
|
} else {
|
||||||
map_fix(&addr, 0);
|
map_fix(dst, 0);
|
||||||
}
|
}
|
||||||
if (addr.sa.sa_family != params.baddr.sin6_family) {
|
if (dst->sa.sa_family != params.baddr.sin6_family) {
|
||||||
LOG(LOG_E, "different addresses family\n");
|
LOG(LOG_E, "different addresses family\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int sfd = nb_socket(addr.sa.sa_family, SOCK_STREAM);
|
int sfd = nb_socket(dst->sa.sa_family, type);
|
||||||
if (sfd < 0) {
|
if (sfd < 0) {
|
||||||
uniperror("socket");
|
uniperror("socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (socket_mod(sfd, &addr.sa) < 0) {
|
if (socket_mod(sfd, &dst->sa) < 0) {
|
||||||
close(sfd);
|
close(sfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (addr.sa.sa_family == AF_INET6) {
|
if (dst->sa.sa_family == AF_INET6) {
|
||||||
int no = 0;
|
int no = 0;
|
||||||
if (setsockopt(sfd, IPPROTO_IPV6,
|
if (setsockopt(sfd, IPPROTO_IPV6,
|
||||||
IPV6_V6ONLY, (char *)&no, sizeof(no))) {
|
IPV6_V6ONLY, (char *)&no, sizeof(no))) {
|
||||||
@ -372,6 +369,19 @@ int create_conn(struct poolhd *pool,
|
|||||||
close(sfd);
|
close(sfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return sfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int create_conn(struct poolhd *pool,
|
||||||
|
struct eval *val, struct sockaddr_ina *dst, int next)
|
||||||
|
{
|
||||||
|
struct sockaddr_ina addr = *dst;
|
||||||
|
|
||||||
|
int sfd = remote_sock(&addr, SOCK_STREAM);
|
||||||
|
if (sfd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int syn_count = 1;
|
int syn_count = 1;
|
||||||
if (setsockopt(sfd, IPPROTO_TCP,
|
if (setsockopt(sfd, IPPROTO_TCP,
|
||||||
@ -424,7 +434,7 @@ int create_conn(struct poolhd *pool,
|
|||||||
pair->in6 = dst->in6;
|
pair->in6 = dst->in6;
|
||||||
#endif
|
#endif
|
||||||
pair->flag = FLAG_CONN;
|
pair->flag = FLAG_CONN;
|
||||||
val->type = EV_IGNORE;
|
//val->type = EV_IGNORE;
|
||||||
|
|
||||||
if (params.debug) {
|
if (params.debug) {
|
||||||
INIT_ADDR_STR((*dst));
|
INIT_ADDR_STR((*dst));
|
||||||
@ -440,25 +450,8 @@ int udp_associate(struct poolhd *pool,
|
|||||||
{
|
{
|
||||||
struct sockaddr_ina addr = *dst;
|
struct sockaddr_ina addr = *dst;
|
||||||
|
|
||||||
int ufd = nb_socket(params.baddr.sin6_family, SOCK_DGRAM);
|
int ufd = remote_sock(&addr, SOCK_DGRAM);
|
||||||
if (ufd < 0) {
|
if (ufd < 0) {
|
||||||
uniperror("socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (params.baddr.sin6_family == AF_INET6) {
|
|
||||||
int no = 0;
|
|
||||||
if (setsockopt(ufd, IPPROTO_IPV6,
|
|
||||||
IPV6_V6ONLY, (char *)&no, sizeof(no))) {
|
|
||||||
uniperror("setsockopt IPV6_V6ONLY");
|
|
||||||
close(ufd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
map_fix(&addr, 6);
|
|
||||||
}
|
|
||||||
if (bind(ufd, (struct sockaddr *)¶ms.baddr,
|
|
||||||
SA_SIZE(¶ms.baddr)) < 0) {
|
|
||||||
uniperror("bind");
|
|
||||||
close(ufd);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
struct eval *pair = add_event(pool, EV_UDP_TUNNEL, ufd, POLLIN);
|
struct eval *pair = add_event(pool, EV_UDP_TUNNEL, ufd, POLLIN);
|
||||||
@ -467,10 +460,6 @@ int udp_associate(struct poolhd *pool,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (dst->in6.sin6_port != 0) {
|
if (dst->in6.sin6_port != 0) {
|
||||||
if (socket_mod(ufd, &addr.sa) < 0) {
|
|
||||||
del_event(pool, pair);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (connect(ufd, &addr.sa, SA_SIZE(&addr)) < 0) {
|
if (connect(ufd, &addr.sa, SA_SIZE(&addr)) < 0) {
|
||||||
uniperror("connect");
|
uniperror("connect");
|
||||||
del_event(pool, pair);
|
del_event(pool, pair);
|
||||||
@ -478,11 +467,6 @@ int udp_associate(struct poolhd *pool,
|
|||||||
}
|
}
|
||||||
pair->in6 = addr.in6;
|
pair->in6 = addr.in6;
|
||||||
}
|
}
|
||||||
if (params.debug) {
|
|
||||||
INIT_ADDR_STR((*dst));
|
|
||||||
LOG(LOG_S, "udp associate: fd=%d, addr=%s:%d\n",
|
|
||||||
ufd, ADDR_STR, ntohs(dst->in.sin_port));
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
socklen_t sz = sizeof(addr);
|
socklen_t sz = sizeof(addr);
|
||||||
|
|
||||||
@ -510,6 +494,11 @@ int udp_associate(struct poolhd *pool,
|
|||||||
close(cfd);
|
close(cfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (params.debug) {
|
||||||
|
INIT_ADDR_STR((*dst));
|
||||||
|
LOG(LOG_S, "udp associate: fds=%d,%d addr=%s:%d\n",
|
||||||
|
ufd, cfd, ADDR_STR, ntohs(dst->in.sin_port));
|
||||||
|
}
|
||||||
val->type = EV_IGNORE;
|
val->type = EV_IGNORE;
|
||||||
val->pair = client;
|
val->pair = client;
|
||||||
client->pair = pair;
|
client->pair = pair;
|
||||||
@ -648,15 +637,14 @@ int on_tunnel(struct poolhd *pool, struct eval *val,
|
|||||||
}
|
}
|
||||||
n = val->buff.size - val->buff.offset;
|
n = val->buff.size - val->buff.offset;
|
||||||
|
|
||||||
ssize_t sn = send(pair->fd,
|
ssize_t sn = tcp_send_hook(pair,
|
||||||
val->buff.data + val->buff.offset, n, 0);
|
val->buff.data + val->buff.offset, n, n);
|
||||||
if (sn != n) {
|
if (sn < 0) {
|
||||||
if (sn < 0 && get_e() != EAGAIN) {
|
uniperror("send");
|
||||||
uniperror("send");
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
if (sn < n) {
|
||||||
if (sn > 0)
|
val->buff.offset += sn;
|
||||||
val->buff.offset += sn;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
free(val->buff.data);
|
free(val->buff.data);
|
||||||
@ -671,44 +659,20 @@ int on_tunnel(struct poolhd *pool, struct eval *val,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
n = recv(val->fd, buffer, bfsize, 0);
|
n = tcp_recv_hook(pool, val, buffer, bfsize);
|
||||||
if (n < 0 && get_e() == EAGAIN) {
|
//if (n < 0 && get_e() == EAGAIN) {
|
||||||
|
if (n == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (n == 0) {
|
|
||||||
if (val->flag != FLAG_CONN)
|
|
||||||
val = val->pair;
|
|
||||||
on_fin(pool, val);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
uniperror("recv");
|
|
||||||
switch (get_e()) {
|
|
||||||
case ECONNRESET:
|
|
||||||
case ETIMEDOUT:
|
|
||||||
if (val->flag == FLAG_CONN)
|
|
||||||
on_torst(pool, val);
|
|
||||||
else
|
|
||||||
on_fin(pool, val->pair);
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->recv_count += n;
|
ssize_t sn = tcp_send_hook(pair, buffer, bfsize, n);
|
||||||
if (!val->last_round) {
|
if (sn < 0) {
|
||||||
val->round_count++;
|
uniperror("send");
|
||||||
val->last_round = 1;
|
return -1;
|
||||||
pair->last_round = 0;
|
|
||||||
}
|
}
|
||||||
|
if (sn < n) {
|
||||||
ssize_t sn = send(pair->fd, buffer, n, 0);
|
|
||||||
if (sn != n) {
|
|
||||||
if (sn < 0) {
|
|
||||||
if (get_e() != EAGAIN) {
|
|
||||||
uniperror("send");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sn = 0;
|
|
||||||
}
|
|
||||||
LOG(LOG_S, "send: %zd != %zd (fd: %d)\n", sn, n, pair->fd);
|
LOG(LOG_S, "send: %zd != %zd (fd: %d)\n", sn, n, pair->fd);
|
||||||
assert(!(val->buff.size || val->buff.offset));
|
assert(!(val->buff.size || val->buff.offset));
|
||||||
|
|
||||||
@ -741,6 +705,8 @@ int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
|
|||||||
data_len -= S_SIZE_I6;
|
data_len -= S_SIZE_I6;
|
||||||
}
|
}
|
||||||
struct sockaddr_ina addr = {0};
|
struct sockaddr_ina addr = {0};
|
||||||
|
struct eval *pair = val->flag == FLAG_CONN ?
|
||||||
|
val->pair : val->pair->pair;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
socklen_t asz = sizeof(addr);
|
socklen_t asz = sizeof(addr);
|
||||||
@ -753,6 +719,11 @@ int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->recv_count += n;
|
val->recv_count += n;
|
||||||
|
if (val->round_sent == 0) {
|
||||||
|
val->round_count++;
|
||||||
|
val->round_sent += n;
|
||||||
|
pair->round_sent = 0;
|
||||||
|
}
|
||||||
ssize_t ns;
|
ssize_t ns;
|
||||||
|
|
||||||
if (val->flag == FLAG_CONN) {
|
if (val->flag == FLAG_CONN) {
|
||||||
@ -774,24 +745,21 @@ int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
|
|||||||
LOG(LOG_E, "udp parse error\n");
|
LOG(LOG_E, "udp parse error\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!val->pair->in6.sin6_port) {
|
if (!pair->in6.sin6_port) {
|
||||||
if (params.baddr.sin6_family == AF_INET6) {
|
if (params.baddr.sin6_family == AF_INET6) {
|
||||||
map_fix(&addr, 6);
|
map_fix(&addr, 6);
|
||||||
}
|
}
|
||||||
if (params.baddr.sin6_family != addr.sa.sa_family) {
|
if (params.baddr.sin6_family != addr.sa.sa_family) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (socket_mod(val->pair->fd, &addr.sa) < 0) {
|
if (connect(pair->fd, &addr.sa, SA_SIZE(&addr)) < 0) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (connect(val->pair->fd, &addr.sa, SA_SIZE(&addr)) < 0) {
|
|
||||||
uniperror("connect");
|
uniperror("connect");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->pair->in6 = addr.in6;
|
pair->in6 = addr.in6;
|
||||||
}
|
}
|
||||||
ns = udp_hook(val->pair, data + offs, bfsize - offs, n - offs,
|
ns = udp_hook(pair, data + offs, bfsize - offs, n - offs,
|
||||||
(struct sockaddr_ina *)&val->pair->in6);
|
(struct sockaddr_ina *)&pair->in6);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
map_fix(&addr, 0);
|
map_fix(&addr, 0);
|
||||||
@ -801,7 +769,7 @@ int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
|
|||||||
if (offs < 0 || offs > S_SIZE_I6) {
|
if (offs < 0 || offs > S_SIZE_I6) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ns = send(val->pair->pair->fd, data - offs, offs + n, 0);
|
ns = send(pair->fd, data - offs, offs + n, 0);
|
||||||
}
|
}
|
||||||
if (ns < 0) {
|
if (ns < 0) {
|
||||||
uniperror("sendto");
|
uniperror("sendto");
|
||||||
@ -906,8 +874,10 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
|
|||||||
uniperror("mod_etype");
|
uniperror("mod_etype");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->type = EV_TUNNEL;
|
int t = params.auto_level <= AUTO_NOBUFF
|
||||||
val->pair->type = EV_DESYNC;
|
? EV_TUNNEL : EV_FIRST_TUNNEL;
|
||||||
|
val->type = t;
|
||||||
|
val->pair->type = t;
|
||||||
}
|
}
|
||||||
if (resp_error(val->pair->fd,
|
if (resp_error(val->pair->fd,
|
||||||
error, val->pair->flag) < 0) {
|
error, val->pair->flag) < 0) {
|
||||||
@ -920,10 +890,13 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
|
|||||||
|
|
||||||
void close_conn(struct poolhd *pool, struct eval *val)
|
void close_conn(struct poolhd *pool, struct eval *val)
|
||||||
{
|
{
|
||||||
LOG(LOG_S, "close: fds=%d,%d, recv: %zd,%zd, rounds: %d,%d\n",
|
struct eval *cval = val;
|
||||||
val->fd, val->pair ? val->pair->fd : -1,
|
do {
|
||||||
val->recv_count, val->pair ? val->pair->recv_count : 0,
|
LOG(LOG_S, "close: fd=%d (pair=%d), recv: %zd, rounds: %d\n",
|
||||||
val->round_count, val->pair ? val->pair->round_count : 0);
|
cval->fd, cval->pair ? cval->pair->fd : -1,
|
||||||
|
cval->recv_count, cval->round_count);
|
||||||
|
cval = cval->pair;
|
||||||
|
} while (cval && cval != val);
|
||||||
del_event(pool, val);
|
del_event(pool, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -977,9 +950,8 @@ int event_loop(int srvfd)
|
|||||||
close_conn(pool, val);
|
close_conn(pool, val);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case EV_PRE_TUNNEL:
|
case EV_FIRST_TUNNEL:
|
||||||
if (on_tunnel_check(pool, val,
|
if (on_first_tunnel(pool, val, buffer, bfsize, etype))
|
||||||
buffer, bfsize, etype & POLLOUT))
|
|
||||||
close_conn(pool, val);
|
close_conn(pool, val);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -998,12 +970,6 @@ int event_loop(int srvfd)
|
|||||||
close_conn(pool, val);
|
close_conn(pool, val);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case EV_DESYNC:
|
|
||||||
if (on_desync(pool, val,
|
|
||||||
buffer, bfsize, etype & POLLOUT))
|
|
||||||
close_conn(pool, val);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case EV_IGNORE:
|
case EV_IGNORE:
|
||||||
if (etype & (POLLHUP | POLLERR | POLLRDHUP))
|
if (etype & (POLLHUP | POLLERR | POLLRDHUP))
|
||||||
close_conn(pool, val);
|
close_conn(pool, val);
|
||||||
|
Loading…
Reference in New Issue
Block a user