1
0
Fork 0
mirror of https://github.com/hufrea/byedpi.git synced 2025-02-03 18:11:10 +03:00

avl, --hosts, --dst

This commit is contained in:
ruti 2024-04-16 20:55:41 +03:00
parent 38d44ec1ca
commit 3b65b275b1
7 changed files with 296 additions and 163 deletions

View file

@ -73,6 +73,7 @@ struct eval {
};
ssize_t recv_count;
int attempt;
char cache;
#ifndef NOEPOLL
uint32_t events;
#endif

109
main.c
View file

@ -17,12 +17,13 @@
#include <netdb.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/mman.h>
#else
#include <ws2tcpip.h>
#define close(fd) closesocket(fd)
#endif
#define VERSION "8.1"
#define VERSION "10"
#define MPOOL_INC 16
@ -71,12 +72,15 @@ const char help_text[] = {
#ifdef TCP_FASTOPEN_CONNECT
" -F, --tfo Enable TCP Fast Open\n"
#endif
" -A, --auto[=t,r,c,s,a] Try desync params after this option\n"
" Detect: torst,redirect,cl_err,sid_inv,alert\n"
" -L, --late-conn Waiting for request before connecting\n"
" -A, --auto[=t,r,c,s,a,n] Try desync params after this option\n"
" Detect: torst,redirect,cl_err,sid_inv,alert,nop\n"
" -u, --cache-ttl <sec> Lifetime of cached desync params for IP\n"
#ifdef TIMEOUT_SUPPORT
" -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n"
#endif
" -H, --hosts <file|:str> Hosts whitelist\n"
" -D, --dst <addr> Custom destination IP\n"
" -s, --split <n[+s]> Split packet at n\n"
" +s - add SNI offset\n"
" +h - add HTTP Host offset\n"
@ -115,11 +119,14 @@ const struct option options[] = {
#ifdef TCP_FASTOPEN_CONNECT
{"tfo ", 0, 0, 'F'},
#endif
{"late-conn", 0, 0, 'L'},
{"auto", 2, 0, 'A'},
{"cache-ttl", 1, 0, 'u'},
#ifdef TIMEOUT_SUPPORT
{"timeout", 1, 0, 'T'},
#endif
{"hosts", 1, 0, 'H'},
{"dst", 1, 0, 'D'},
{"split", 1, 0, 's'},
{"disorder", 1, 0, 'd'},
{"oob", 1, 0, 'o'},
@ -195,16 +202,27 @@ char *ftob(const char *str, ssize_t *sl)
long size;
FILE *file = fopen(str, "rb");
if (!file)
if (!file) {
return 0;
}
do {
if (fseek(file, 0, SEEK_END)) {
break;
}
size = ftell(file);
if (!size || fseek(file, 0, SEEK_SET)) {
if (size <= 0) {
break;
}
if (fseek(file, 0, SEEK_SET)) {
break;
}
#ifndef _WIN32
buffer = mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file), 0);
if (buffer == MAP_FAILED) {
buffer = 0;
break;
}
#else
if (!(buffer = malloc(size))) {
break;
}
@ -212,6 +230,7 @@ char *ftob(const char *str, ssize_t *sl)
free(buffer);
buffer = 0;
}
#endif
} while (0);
if (buffer) {
*sl = size;
@ -221,6 +240,33 @@ char *ftob(const char *str, ssize_t *sl)
}
struct mphdr *parse_hosts(char *buffer, size_t size)
{
struct mphdr *hdr = mem_pool(1);
if (!hdr) {
return 0;
}
char *end = buffer + size;
char *e = buffer, *s = buffer;
for (; e <= end; e++) {
if (*e != ' ' && *e != '\n' && e != end) {
continue;
}
if (s == e) {
s++;
continue;
}
if (mem_add(hdr, s, e - s) == 0) {
free(hdr);
return 0;
}
s = e + 1;
}
return hdr;
}
int get_addr(const char *str, struct sockaddr_ina *addr)
{
struct addrinfo hints = {0}, *res = 0;
@ -284,18 +330,23 @@ int parse_offset(struct part *part, const char *str)
void *add(void **root, int *n, size_t ss)
{
void *p = realloc(*root, ss * (*n + 1));
char *p = realloc(*root, ss * (*n + 1));
if (!p) {
uniperror("realloc");
return 0;
}
*root = p;
p = ((*root) + ((*n) * ss));
p = (p + ((*n) * ss));
memset(p, 0, ss);
*n = *n + 1;
return p;
}
#ifndef _WIN32
#define FREE(p, s) munmap(p, s)
#else
#define FREE(p, s) free(p)
#endif
void clear_params(void)
{
@ -322,15 +373,15 @@ void clear_params(void)
params.dp = 0;
}
if (fake_tls.data != tls_data) {
free(fake_tls.data);
FREE(fake_tls.data, fake_tls.size);
fake_tls.data = tls_data;
}
if (fake_http.data != http_data) {
free(fake_http.data);
FREE(fake_http.data, fake_http.size);
fake_http.data = http_data;
}
if (oob_data.data != oob_char) {
free(oob_data.data);
FREE(oob_data.data, oob_data.size);
oob_data.data = oob_char;
}
}
@ -382,6 +433,7 @@ int main(int argc, char **argv)
clear_params();
return -1;
}
while (!invalid && (rez = getopt_long_only(
argc, argv, opt, options, 0)) != -1) {
switch (rez) {
@ -445,6 +497,10 @@ int main(int argc, char **argv)
// desync options
case 'L':
params.late_conn = 1;
break;
case 'K':
params.de_known = 1;
break;
@ -482,6 +538,8 @@ int main(int argc, char **argv)
case 'a':
dp->detect |= DETECT_TLS_ALERT;
break;
case 'n':
break;
default:
invalid = 1;
continue;
@ -512,6 +570,27 @@ int main(int argc, char **argv)
params.timeout = val;
break;
case 'H':;
char *data = ftob(optarg, &val);
if (!data) {
uniperror("read/parse");
invalid = 1;
}
dp->hosts = parse_hosts(data, val);
if (!dp->hosts) {
perror("parse_hosts");
clear_params();
return -1;
}
break;
case 'D':
if (get_addr(optarg, (struct sockaddr_ina *)&dp->addr) < 0)
invalid = 1;
else
dp->to_ip = 2;
break;
case 's':
case 'd':
case 'o':
@ -671,6 +750,14 @@ int main(int argc, char **argv)
clear_params();
return -1;
}
if (dp->hosts) {
dp = add((void *)&params.dp,
&params.dp_count, sizeof(struct desync_params));
if (!dp) {
clear_params();
return -1;
}
}
s.in.sin_port = port;
b.in.sin_port = 0;
@ -683,7 +770,7 @@ int main(int argc, char **argv)
return -1;
}
}
params.mempool = mem_pool(MPOOL_INC);
params.mempool = mem_pool(0);
if (!params.mempool) {
uniperror("mem_pool");
clear_params();

151
mpool.c
View file

@ -3,129 +3,98 @@
#include <mpool.h>
struct mphdr *mem_pool(int count)
static inline int scmp(const struct elem *p, const struct elem *q)
{
struct mphdr *hdr = malloc(sizeof(struct mphdr));
if (!hdr) {
return 0;
if (p->len != q ->len) {
return p->len < q->len ? -1 : 1;
}
hdr->inc = count;
hdr->max = count;
hdr->count = 0;
return memcmp(p->data, q->data, p->len);
}
hdr->values = malloc(sizeof(*hdr->values) * count);
if (!hdr->values) {
free(hdr);
hdr = 0;
KAVL_INIT(my, struct elem, head, scmp)
struct mphdr *mem_pool(bool cst)
{
struct mphdr *hdr = calloc(sizeof(struct mphdr), 1);
if (hdr) {
hdr->stat = cst;
}
return hdr;
}
int mem_index(struct mphdr *hdr, char *str, int len)
struct elem *mem_get(struct mphdr *hdr, char *str, int len)
{
if (!hdr->count) {
return -2;
}
int s = 0, m, i;
int e = hdr->count - 1;
struct {
int len;
char *data;
} temp = { .len = len, .data = str };
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));
return kavl_find(my, hdr->root, (struct elem *)&temp, 0);
}
struct elem *mem_add(struct mphdr *hdr, char *str, int len, int pos)
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;
}
if (pos >= 0) {
return hdr->values[pos];
}
pos = -pos - 2;
struct elem *val = malloc(sizeof(struct elem) + len);
if (!val) {
struct elem *v, *e = malloc(sizeof(struct elem));
if (!e) {
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);
e->len = len;
if (!hdr->stat) {
e->data = malloc(len);
if (!e->data) {
free(e);
return 0;
}
memcpy(e->data, str, len);
}
hdr->values[pos] = val;
hdr->count++;
return val;
else {
e->data = str;
}
v = kavl_insert(my, &hdr->root, e, 0);
if (e != v) {
if (!hdr->stat) {
free(e->data);
}
free(e);
}
return v;
}
void mem_delete(struct mphdr *hdr, int pos)
void mem_delete(struct mphdr *hdr, char *str, int len)
{
int max = hdr->max;
if (!hdr->count) {
struct {
int len;
char *data;
} temp = { .len = len, .data = str };
struct elem *e = kavl_erase(my, &hdr->root, (struct elem *)&temp, 0);
if (!e) {
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;
}
if (!hdr->stat) {
free(e->data);
e->data = 0;
}
free(hdr->values[pos]);
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--;
free(e);
}
void mem_destroy(struct mphdr *hdr)
{
for (int i = 0; i < hdr->count && hdr->values; i++) {
struct elem *e = hdr->values[i];
while (hdr->root) {
struct elem *e = kavl_erase_first(my, &hdr->root);
if (!e) {
continue;
break;
}
if (!hdr->stat && e->data) {
free(e->data);
}
e->data = 0;
free(e);
hdr->values[i] = 0;
}
free(hdr->values);
memset(hdr, 0, sizeof(*hdr));
free(hdr);
}

29
mpool.h
View file

@ -1,19 +1,26 @@
#include <stdbool.h>
#include <time.h>
#include "kavl.h"
struct elem {
int len;
char *data;
int m;
time_t time;
int len;
char data[];
KAVL_HEAD(struct elem) head;
};
struct mphdr {
int max;
int inc;
int count;
struct elem **values;
bool stat;
struct elem *root;
};
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, int pos);
void mem_delete(struct mphdr *hdr, int pos);
void mem_destroy(struct mphdr *hdr);
struct mphdr *mem_pool(bool cst);
struct elem *mem_get(struct mphdr *hdr, char *str, int len);
struct elem *mem_add(struct mphdr *hdr, char *str, int len);
void mem_delete(struct mphdr *hdr, char *str, int len);
void mem_destroy(struct mphdr *hdr);

View file

@ -56,6 +56,10 @@ struct desync_params {
int tlsrec_n;
struct part *tlsrec;
int detect;
struct mphdr *hosts;
char to_ip;
struct sockaddr_in6 addr;
};
struct params {
@ -67,6 +71,7 @@ struct params {
int def_ttl;
char custom_ttl;
char late_conn;
char tfo;
unsigned int timeout;
long cache_ttl;

147
proxy.c
View file

@ -497,34 +497,26 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
int mode_add_get(struct sockaddr_ina *dst, int m)
{
// m < 0: get, m > 0: set, m == 0: delete
int len;
time_t t;
struct elem *val;
struct {
uint16_t port;
union {
struct in_addr ip4;
struct in6_addr ip6;
};
} str = { .port = dst->in.sin_port };
char *str = (char *)&dst->in;
int len = sizeof(dst->sa.sa_family);
if (dst->sa.sa_family == AF_INET) {
str.ip4 = dst->in.sin_addr;
len = sizeof(str.port) + sizeof(str.ip4);
len = sizeof(dst->in);
}
else {
str.ip6 = dst->in6.sin6_addr;
len = sizeof(str);
len = sizeof(dst->in6) - sizeof(dst->in6.sin6_scope_id);
}
int i = mem_index(params.mempool, (char *)&str, len);
if (m == 0 && i >= 0) {
mem_delete(params.mempool, i);
len -= sizeof(dst->sa.sa_family);
if (m == 0) {
mem_delete(params.mempool, str, len);
return 0;
}
else if (m > 0) {
time(&t);
val = mem_add(params.mempool, (char *)&str, len, i);
val = mem_add(params.mempool, str, len);
if (!val) {
uniperror("mem_add");
return -1;
@ -533,10 +525,10 @@ int mode_add_get(struct sockaddr_ina *dst, int m)
val->time = t;
return 0;
}
if (i < 0) {
val = mem_get(params.mempool, str, len);
if (!val) {
return -1;
}
val = params.mempool->values[i];
time(&t);
if (t > val->time + params.cache_ttl) {
LOG(LOG_S, "time=%ld, now=%ld, ignore\n", val->time, t);
@ -546,6 +538,19 @@ int mode_add_get(struct sockaddr_ina *dst, int m)
}
int ext_connect(struct poolhd *pool, struct eval *val,
struct sockaddr_ina *dst, int next, int m)
{
struct desync_params *dp = &params.dp[m];
if (dp->to_ip == 2) {
struct sockaddr_ina addr = { .in6 = dp->addr };
addr.in.sin_port = dst->in.sin_port;
return create_conn(pool, val, &addr, next);
}
return create_conn(pool, val, dst, next);
}
static inline int on_request(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
@ -584,18 +589,26 @@ static inline int on_request(struct poolhd *pool, struct eval *val,
}
return -1;
}
error = create_conn(pool, val, &dst, EV_CONNECT);
if (params.late_conn) {
val->type = EV_DESYNC;
if (resp_error(val->fd, 0, val->flag) < 0) {
perror("send");
return -1;
}
val->in6 = dst.in6;
return 0;
}
int m = mode_add_get(&dst, -1);
val->cache = (m == 0);
val->attempt = m < 0 ? 0 : m;
error = ext_connect(pool, val, &dst, EV_CONNECT, m);
if (error) {
int en = get_e();
if (resp_error(val->fd, en ? en : error, val->flag) < 0)
uniperror("send");
return -1;
}
int m = mode_add_get(&dst, -1);
if (m >= 0) {
val->attempt = m;
}
val->pair->attempt = m;
val->type = EV_IGNORE;
return 0;
}
@ -605,8 +618,8 @@ int reconnect(struct poolhd *pool, struct eval *val, int m)
{
struct eval *client = val->pair;
if (create_conn(pool, client,
(struct sockaddr_ina *)&val->in6, EV_DESYNC)) {
if (ext_connect(pool, client,
(struct sockaddr_ina *)&val->in6, EV_DESYNC, m)) {
return -1;
}
val->pair = 0;
@ -614,19 +627,34 @@ int reconnect(struct poolhd *pool, struct eval *val, int m)
client->type = EV_IGNORE;
client->attempt = m;
client->cache = 1;
return 0;
}
bool check_host(struct mphdr *hosts, struct eval *val)
{
char *host;
int len;
if (!(len = parse_tls(val->buff.data, val->buff.size, &host))) {
len = parse_http(val->buff.data, val->buff.size, &host, 0);
}
return mem_get(hosts, host, len) != 0;
}
int on_torst(struct poolhd *pool, struct eval *val)
{
int m = val->pair->attempt + 1;
for (; m < params.dp_count; m++) {
struct desync_params dp = params.dp[m];
if (dp.detect == 0
|| (dp.detect & DETECT_TORST))
struct desync_params *dp = &params.dp[m];
if (!(dp->detect & DETECT_TORST)) {
continue;
}
if (!dp->hosts || check_host(dp->hosts, val->pair)) {
break;
}
}
if (m >= params.dp_count) {
mode_add_get(
@ -646,25 +674,34 @@ int on_response(struct poolhd *pool, struct eval *val,
ssize_t qn = val->pair->buff.size;
for (; m < params.dp_count; m++) {
struct desync_params dp = params.dp[m];
struct desync_params *dp = &params.dp[m];
if ((dp.detect & DETECT_HTTP_LOCAT)
&& is_http_redirect(req, qn, resp, sn)) {
break;
}
if ((dp.detect & DETECT_TLS_INVSID)
&& neq_tls_sid(req, qn, resp, sn)) {
break;
}
if ((dp.detect & DETECT_TLS_ALERT)
&& is_tls_alert(resp, sn)) {
break;
}
if (dp.detect & DETECT_HTTP_CLERR) {
int code = get_http_code(resp, sn);
if (code > 400 && code < 451 && code != 429) {
switch (0) {
default:
if ((dp->detect & DETECT_HTTP_LOCAT)
&& is_http_redirect(req, qn, resp, sn)) {
break;
}
else if ((dp->detect & DETECT_TLS_INVSID)
&& neq_tls_sid(req, qn, resp, sn)
&& !neq_tls_sid(
fake_tls.data, fake_tls.size, resp, sn)) {
break;
}
else if ((dp->detect & DETECT_TLS_ALERT)
&& is_tls_alert(resp, sn)) {
break;
}
else if (dp->detect & DETECT_HTTP_CLERR) {
int code = get_http_code(resp, sn);
if (code > 400 && code < 451 && code != 429) {
break;
}
}
continue;
}
if (!dp->hosts || check_host(dp->hosts, val->pair)) {
break;
}
}
if (m < params.dp_count) {
@ -715,8 +752,7 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
}
int m = pair->attempt;
if ((m == 0 && val->attempt < 0)
|| (m && m == val->attempt)) {
if (!pair->cache) {
return 0;
}
if (m == 0) {
@ -757,6 +793,21 @@ int on_desync(struct poolhd *pool, struct eval *val,
return -1;
}
memcpy(val->buff.data, buffer, n);
if (!m) for (; m < params.dp_count; m++) {
struct desync_params *dp = &params.dp[m];
if (!dp->detect &&
(!dp->hosts || check_host(dp->hosts, val))) {
break;
}
}
if (m >= params.dp_count) return -1;
val->attempt = m;
if (params.late_conn) {
return ext_connect(pool, val,
(struct sockaddr_ina *)&val->in6, EV_DESYNC, m);
}
}
else {
n = val->buff.size;

View file

@ -40,7 +40,11 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
Если сервер его поддерживает, то первый пакет будет отправлен сразу вместе с SYN
Поддерживается только в Linux (4.11+)
-A, --auto[=t,r,c,s,a]
-L, --late-conn
Выполнять настоящее подключение только после получения первого пакета от клиента
Полезно при сочетании --hosts с --dst
-A, --auto[=t,r,c,s,a,n]
Автоматический режим
Если произошло событие, похожее на блокировку или поломку,
то будут применены параметры обхода, следующие за данной опцией
@ -50,11 +54,12 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
cl_err : HTTP ответ, код которого равен 40x, но не 429
sid_inv : session_id в TLS ServerHello и ClientHello не совпадают
alert : TLS Error Alert в ответе
nop : Предыдущая группа пропущена, например из-за ограничения по hosts
По умолчанию обрабатывается только torst
Можно указывать несколько групп опций, раделяя их данным параметром
Если соединение успешно прошло, то параметры для данного IP будут закешированны
Параметры, которые можно вынести в отдельную группу:
split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec
hosts, dst, split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec
Пример:
--auto=redirect --split=1+h --auto=torst --fake -1 --auto=sid_inv,alert --tlsrec 1+s
@ -66,6 +71,14 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
В Linux переводится в миллисекунды, поэтому можно указать дробное число
Истечение таймаута будет обработано --auto
-H, --hosts <file|:string>
Ограничить область действия параметров списком доменов
Домены должны быть разделены новой строкой или пробелом
-D, --dst <ip>
Заменить адрес назначения из запроса на указанный
Полезно совмещать с --auto и --hosts
-s, --split <n[+s]>
Разбить запрос по указанному смещению
После числа можно добавить флаг: