mirror of
https://github.com/hufrea/byedpi.git
synced 2024-12-22 06:15:14 +00:00
Merge branch 'hufrea:main' into cmake
This commit is contained in:
commit
f265ab4b24
7
Makefile
7
Makefile
@ -10,6 +10,9 @@ WIN_SRC = win_service.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
WIN_OBJ = $(WIN_SRC:.c=.o)
|
||||
|
||||
PREFIX := /usr/local
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin/
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
@ -23,3 +26,7 @@ windows: $(OBJ) $(WIN_OBJ)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(TARGET).exe $(OBJ) $(WIN_OBJ)
|
||||
|
||||
install: $(TARGET)
|
||||
mkdir -p $(INSTALL_DIR)
|
||||
install -m 755 $(TARGET) $(INSTALL_DIR)
|
||||
|
11
README.md
11
README.md
@ -16,6 +16,9 @@ ciadpi --fake -1 --ttl 8
|
||||
-p, --port <num>
|
||||
Прослушиваемый порт, по умолчанию 1080
|
||||
|
||||
-E, --transparent
|
||||
Запуск в режиме прозрачного прокси, SOCKS работать не будет
|
||||
|
||||
-c, --max-conn <count>
|
||||
Максимальное количество клиентских подключений, по умолчанию 512
|
||||
|
||||
@ -53,6 +56,12 @@ ciadpi --fake -1 --ttl 8
|
||||
ssl_err : В ответ на ClientHello не пришел ServerHello или SH содержит некорректный session_id
|
||||
none : Предыдущая группа пропущена, например из-за ограничения по доменам или протоколам
|
||||
|
||||
-L, --auto-mode <0|1>
|
||||
0: кешировать IP только если имеется возможность переподключиться
|
||||
1: кешировать IP также в том случае, если:
|
||||
torst - таймаут/соединение сброшено во время обмена пакетами (т.е. уже после первых данных от сервера)
|
||||
ssl_err - совершился лишь один круг обмена данными (запрос-ответ/запрос-ответ-запрос)
|
||||
|
||||
-u, --cache-ttl <sec>
|
||||
Время жизни значения в кеше, по умолчанию 100800 (28 часов)
|
||||
|
||||
@ -246,7 +255,7 @@ TCP может отсылать данные вне основного пото
|
||||
------
|
||||
#### Примеры:
|
||||
```
|
||||
--fake -1 --ttl 10 --auto=alert,sid_inv --fake -1 --ttl 5
|
||||
--fake -1 --ttl 10 --auto=ssl_err --fake -1 --ttl 5
|
||||
```
|
||||
По умолчанию использовать `fake` с ttl=10, в случае ошибки использовать `fake` с ttl=5
|
||||
|
||||
|
21
conev.c
21
conev.c
@ -4,18 +4,20 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include "error.h"
|
||||
|
||||
|
||||
struct poolhd *init_pool(int count)
|
||||
{
|
||||
struct poolhd *pool = calloc(sizeof(struct poolhd), 1);
|
||||
if (!pool) {
|
||||
uniperror("init pool");
|
||||
return 0;
|
||||
}
|
||||
pool->max = count;
|
||||
pool->count = 0;
|
||||
pool->iters = 0;
|
||||
|
||||
|
||||
#ifndef NOEPOLL
|
||||
int efd = epoll_create(count);
|
||||
if (efd < 0) {
|
||||
@ -27,8 +29,9 @@ struct poolhd *init_pool(int count)
|
||||
pool->pevents = malloc(sizeof(*pool->pevents) * count);
|
||||
pool->links = malloc(sizeof(*pool->links) * count);
|
||||
pool->items = malloc(sizeof(*pool->items) * count);
|
||||
|
||||
|
||||
if (!pool->pevents || !pool->links || !pool->items) {
|
||||
uniperror("init pool");
|
||||
destroy_pool(pool);
|
||||
return 0;
|
||||
}
|
||||
@ -45,19 +48,21 @@ struct eval *add_event(struct poolhd *pool, enum eid type,
|
||||
{
|
||||
assert(fd > 0);
|
||||
if (pool->count >= pool->max) {
|
||||
LOG(LOG_E, "add_event: pool is full\n");
|
||||
return 0;
|
||||
}
|
||||
struct eval *val = pool->links[pool->count];
|
||||
memset(val, 0, sizeof(*val));
|
||||
|
||||
|
||||
val->mod_iter = pool->iters;
|
||||
val->fd = fd;
|
||||
val->index = pool->count;
|
||||
val->type = type;
|
||||
|
||||
|
||||
#ifndef NOEPOLL
|
||||
struct epoll_event ev = { .events = EPOLLRDHUP | e, .data = {val} };
|
||||
if (epoll_ctl(pool->efd, EPOLL_CTL_ADD, fd, &ev)) {
|
||||
uniperror("add event");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@ -67,7 +72,7 @@ struct eval *add_event(struct poolhd *pool, enum eid type,
|
||||
pfd->events = POLLRDHUP | e;
|
||||
pfd->revents = 0;
|
||||
#endif
|
||||
|
||||
|
||||
pool->count++;
|
||||
return val;
|
||||
}
|
||||
@ -153,9 +158,6 @@ struct eval *next_event(struct poolhd *pool, int *offs, int *type)
|
||||
if (i < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (pool->iters == UINT_MAX) {
|
||||
pool->iters = 0;
|
||||
}
|
||||
pool->iters++;
|
||||
}
|
||||
struct eval *val = pool->pevents[i].data.ptr;
|
||||
@ -188,9 +190,6 @@ struct eval *next_event(struct poolhd *pool, int *offs, int *typel)
|
||||
return 0;
|
||||
}
|
||||
i = pool->count - 1;
|
||||
if (pool->iters == UINT_MAX) {
|
||||
pool->iters = 0;
|
||||
}
|
||||
pool->iters++;
|
||||
}
|
||||
short type = pool->pevents[i].revents;
|
||||
|
7
conev.h
7
conev.h
@ -68,7 +68,7 @@ struct buffer {
|
||||
struct eval {
|
||||
int fd;
|
||||
int index;
|
||||
unsigned int mod_iter;
|
||||
unsigned long long mod_iter;
|
||||
enum eid type;
|
||||
struct eval *pair;
|
||||
struct buffer buff;
|
||||
@ -78,8 +78,11 @@ struct eval {
|
||||
struct sockaddr_in6 in6;
|
||||
};
|
||||
ssize_t recv_count;
|
||||
unsigned int round_count;
|
||||
char last_round;
|
||||
int attempt;
|
||||
char cache;
|
||||
char mark; //
|
||||
};
|
||||
|
||||
struct poolhd {
|
||||
@ -93,7 +96,7 @@ struct poolhd {
|
||||
#else
|
||||
struct pollfd *pevents;
|
||||
#endif
|
||||
unsigned int iters;
|
||||
unsigned long long iters;
|
||||
};
|
||||
|
||||
struct poolhd *init_pool(int count);
|
||||
|
47
desync.c
47
desync.c
@ -1,3 +1,5 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "desync.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -16,11 +18,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#else
|
||||
#include <linux/tcp.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <linux/filter.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define memfd_create(name, flags) syscall(__NR_memfd_create, name, flags)
|
||||
#endif
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
@ -143,14 +141,12 @@ void wait_send(int sfd)
|
||||
#define wait_send_if_support(sfd) // :(
|
||||
#endif
|
||||
|
||||
#ifdef FAKE_SUPPORT
|
||||
#ifndef _WIN32
|
||||
#ifdef __linux__
|
||||
ssize_t send_fake(int sfd, char *buffer,
|
||||
int cnt, long pos, int fa, struct desync_params *opt)
|
||||
{
|
||||
struct sockaddr_in6 addr = {};
|
||||
socklen_t addr_size = sizeof(addr);
|
||||
#ifdef __linux__
|
||||
if (opt->md5sig) {
|
||||
if (getpeername(sfd,
|
||||
(struct sockaddr *)&addr, &addr_size) < 0) {
|
||||
@ -158,7 +154,6 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
struct packet pkt;
|
||||
if (opt->fake_data.data) {
|
||||
pkt = opt->fake_data;
|
||||
@ -173,21 +168,16 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
}
|
||||
else pkt.size = 0;
|
||||
}
|
||||
|
||||
int ffd = memfd_create("name", 0);
|
||||
if (ffd < 0) {
|
||||
uniperror("memfd_create");
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
uniperror("pipe");
|
||||
return -1;
|
||||
}
|
||||
char *p = 0;
|
||||
ssize_t len = -1;
|
||||
|
||||
while (1) {
|
||||
if (ftruncate(ffd, pos) < 0) {
|
||||
uniperror("ftruncate");
|
||||
break;
|
||||
}
|
||||
p = mmap(0, pos, PROT_WRITE, MAP_SHARED, ffd, 0);
|
||||
p = mmap(0, pos, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||
if (p == MAP_FAILED) {
|
||||
uniperror("mmap");
|
||||
p = 0;
|
||||
@ -198,8 +188,6 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
if (setttl(sfd, opt->ttl ? opt->ttl : 8, fa) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (opt->md5sig) {
|
||||
struct tcp_md5sig md5 = {
|
||||
.tcpm_keylen = 5
|
||||
@ -212,17 +200,22 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (opt->ip_options && fa == AF_INET
|
||||
&& setsockopt(sfd, IPPROTO_IP, IP_OPTIONS,
|
||||
opt->ip_options, opt->ip_options_len) < 0) {
|
||||
uniperror("setsockopt IP_OPTIONS");
|
||||
break;
|
||||
}
|
||||
struct iovec vec = { .iov_base = p, .iov_len = pos };
|
||||
|
||||
len = sendfile(sfd, ffd, 0, pos);
|
||||
len = vmsplice(fds[1], &vec, 1, SPLICE_F_GIFT);
|
||||
if (len < 0) {
|
||||
uniperror("sendfile");
|
||||
uniperror("vmsplice");
|
||||
break;
|
||||
}
|
||||
len = splice(fds[0], 0, sfd, 0, len, 0);
|
||||
if (len < 0) {
|
||||
uniperror("splice");
|
||||
break;
|
||||
}
|
||||
wait_send(sfd);
|
||||
@ -237,7 +230,6 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
uniperror("setsockopt IP_OPTIONS");
|
||||
break;
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (opt->md5sig) {
|
||||
struct tcp_md5sig md5 = {
|
||||
.tcpm_keylen = 0
|
||||
@ -250,14 +242,16 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (p) munmap(p, pos);
|
||||
close(ffd);
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
OVERLAPPED ov = {};
|
||||
|
||||
ssize_t send_fake(int sfd, char *buffer,
|
||||
@ -359,7 +353,6 @@ ssize_t send_fake(int sfd, char *buffer,
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ssize_t send_oob(int sfd, char *buffer,
|
||||
ssize_t n, long pos, char *c)
|
||||
|
38
dist/linux/README.md
vendored
Normal file
38
dist/linux/README.md
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# Installing on Linux
|
||||
|
||||
## Building
|
||||
```sh
|
||||
cd byedpi/
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Systemd Service (optional)
|
||||
|
||||
You can configure the program to run as systemd service, user- or system-wide (only one at a time).
|
||||
|
||||
### As user service:
|
||||
|
||||
```sh
|
||||
cp byedpi.service ~/.config/systemd/user/
|
||||
cp byedpi.conf ~/.config/
|
||||
systemctl --user enable --now byedpi.service
|
||||
```
|
||||
|
||||
You should see the service now marked as "active":
|
||||
```sh
|
||||
systemctl --user status byedpi.service
|
||||
```
|
||||
|
||||
### As system service:
|
||||
|
||||
```sh
|
||||
sudo cp byedpi.service /etc/systemd/system/
|
||||
sudo cp byedpi.conf /etc/
|
||||
sudo systemctl enable --now byedpi.service
|
||||
```
|
||||
|
||||
You should see the service now marked as "active":
|
||||
```sh
|
||||
systemctl status byedpi.service
|
||||
```
|
8
dist/linux/byedpi.conf
vendored
Normal file
8
dist/linux/byedpi.conf
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# More options and their descriptions can be found here:
|
||||
# https://github.com/hufrea/byedpi/blob/main/README.md
|
||||
#
|
||||
# By default, ciadpi listens on all interfaces,
|
||||
# a specific one can be specified via "--ip 127.0.0.1".
|
||||
|
||||
# Put your options here
|
||||
BYEDPI_OPTIONS="--split 1 --disorder 3+s --mod-http=h,d --auto=torst --tlsrec 1+s"
|
19
dist/linux/byedpi.service
vendored
Normal file
19
dist/linux/byedpi.service
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=ByeDPI
|
||||
Documentation=https://github.com/hufrea/byedpi
|
||||
Wants=network-online.target
|
||||
After=network-online.target nss-lookup.target
|
||||
|
||||
[Service]
|
||||
NoNewPrivileges=yes
|
||||
StandardOutput=null
|
||||
StandardError=journal
|
||||
EnvironmentFile=-/etc/byedpi.conf
|
||||
EnvironmentFile=-%h/.config/byedpi.conf
|
||||
ExecStart=ciadpi $BYEDPI_OPTIONS
|
||||
TimeoutStopSec=5s
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
2
error.h
2
error.h
@ -11,6 +11,8 @@
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include "params.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define get_e() \
|
||||
unie(WSAGetLastError())
|
||||
|
180
extend.c
180
extend.c
@ -23,6 +23,8 @@
|
||||
#include "desync.h"
|
||||
#include "packets.h"
|
||||
|
||||
#define KEY_SIZE sizeof(struct sockaddr_ina)
|
||||
|
||||
|
||||
int set_timeout(int fd, unsigned int s)
|
||||
{
|
||||
@ -45,32 +47,67 @@ int set_timeout(int fd, unsigned int s)
|
||||
}
|
||||
|
||||
|
||||
int mode_add_get(struct sockaddr_ina *dst, int m)
|
||||
static ssize_t serialize_addr(const struct sockaddr_ina *dst,
|
||||
uint8_t *const out, const size_t out_len)
|
||||
{
|
||||
#define serialize(raw, field, len, counter){ \
|
||||
const size_t size = sizeof(field); \
|
||||
if ((counter + size) <= len) { \
|
||||
memcpy(raw + counter, &(field), size); \
|
||||
counter += size; \
|
||||
} else return 0; \
|
||||
}
|
||||
size_t c = 0;
|
||||
serialize(out, dst->in.sin_port, out_len, c);
|
||||
serialize(out, dst->sa.sa_family, out_len, c);
|
||||
|
||||
if (dst->sa.sa_family == AF_INET) {
|
||||
serialize(out, dst->in.sin_addr, out_len, c);
|
||||
} else {
|
||||
serialize(out, dst->in6.sin6_addr, out_len, c);
|
||||
}
|
||||
#undef serialize
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static int mode_add_get(struct sockaddr_ina *dst, int m)
|
||||
{
|
||||
// m < 0: get, m > 0: set, m == 0: delete
|
||||
assert(m >= -1 && m < params.dp_count);
|
||||
|
||||
time_t t = 0;
|
||||
struct elem *val = 0;
|
||||
char *str = (char *)&dst->in;
|
||||
int len = 0;
|
||||
|
||||
if (dst->sa.sa_family == AF_INET) {
|
||||
len = sizeof(dst->in);
|
||||
}
|
||||
else {
|
||||
len = sizeof(dst->in6) - sizeof(dst->in6.sin6_scope_id);
|
||||
}
|
||||
len -= sizeof(dst->sa.sa_family);
|
||||
uint8_t key[KEY_SIZE] = { 0 };
|
||||
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));
|
||||
|
||||
if (m == 0) {
|
||||
mem_delete(params.mempool, str, len);
|
||||
LOG(LOG_S, "delete ip: %s\n", ADDR_STR);
|
||||
mem_delete(params.mempool, (char *)key, len);
|
||||
return 0;
|
||||
}
|
||||
else if (m > 0) {
|
||||
else {
|
||||
LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m);
|
||||
time(&t);
|
||||
val = mem_add(params.mempool, str, len);
|
||||
|
||||
val = mem_add(params.mempool, (char *)key, len);
|
||||
if (!val) {
|
||||
uniperror("mem_add");
|
||||
return -1;
|
||||
@ -79,16 +116,6 @@ int mode_add_get(struct sockaddr_ina *dst, int m)
|
||||
val->time = t;
|
||||
return 0;
|
||||
}
|
||||
val = mem_get(params.mempool, str, len);
|
||||
if (!val) {
|
||||
return -1;
|
||||
}
|
||||
time(&t);
|
||||
if (t > val->time + params.cache_ttl) {
|
||||
LOG(LOG_S, "time=%ld, now=%ld, ignore\n", val->time, t);
|
||||
return 0;
|
||||
}
|
||||
return val->m;
|
||||
}
|
||||
|
||||
|
||||
@ -188,21 +215,39 @@ 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 = ¶ms.dp[m];
|
||||
if (!dp->detect) {
|
||||
return -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 (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);
|
||||
}
|
||||
if (m >= params.dp_count) {
|
||||
mode_add_get(
|
||||
(struct sockaddr_ina *)&val->in6, 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;
|
||||
}
|
||||
return reconnect(pool, val, m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -210,21 +255,44 @@ int on_fin(struct poolhd *pool, struct eval *val)
|
||||
{
|
||||
int m = val->pair->attempt + 1;
|
||||
|
||||
bool can_reconn = (
|
||||
val->pair->buff.data && !val->recv_count
|
||||
);
|
||||
if (!can_reconn && params.auto_level < 1) {
|
||||
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;
|
||||
}
|
||||
for (; m < params.dp_count; m++) {
|
||||
struct desync_params *dp = ¶ms.dp[m];
|
||||
if (!dp->detect) {
|
||||
return -1;
|
||||
}
|
||||
if (!(dp->detect & DETECT_TLS_ERR)) {
|
||||
continue;
|
||||
if (dp->detect & DETECT_TLS_ERR) {
|
||||
if (can_reconn)
|
||||
return reconnect(pool, val, m);
|
||||
else {
|
||||
mode_add_get(
|
||||
(struct sockaddr_ina *)&val->in6, m);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
char *req = val->pair->buff.data;
|
||||
ssize_t qn = val->pair->buff.size;
|
||||
|
||||
if (!is_tls_chello(req, qn)) {
|
||||
continue;
|
||||
}
|
||||
return reconnect(pool, val, m);
|
||||
}
|
||||
if (m > 1) { // delete
|
||||
mode_add_get(
|
||||
(struct sockaddr_ina *)&val->in6, 0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -279,20 +347,25 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
||||
assert(!out);
|
||||
ssize_t n = recv(val->fd, buffer, bfsize, 0);
|
||||
if (n < 1) {
|
||||
if (n) uniperror("recv");
|
||||
if (!n) {
|
||||
return on_fin(pool, val);
|
||||
}
|
||||
uniperror("recv");
|
||||
switch (get_e()) {
|
||||
case ECONNRESET:
|
||||
case ECONNREFUSED:
|
||||
case ETIMEDOUT:
|
||||
return on_torst(pool, val);
|
||||
}
|
||||
return on_fin(pool, val);
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
if (on_response(pool, val, buffer, n) == 0) {
|
||||
return 0;
|
||||
}
|
||||
val->recv_count += n;
|
||||
val->round_count = 1;
|
||||
val->last_round = 1;
|
||||
struct eval *pair = val->pair;
|
||||
|
||||
ssize_t sn = send(pair->fd, buffer, n, 0);
|
||||
@ -300,9 +373,12 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
||||
uniperror("send");
|
||||
return -1;
|
||||
}
|
||||
if (params.auto_level > 0 && params.dp_count > 1) {
|
||||
val->mark = is_tls_chello(pair->buff.data, pair->buff.size);
|
||||
}
|
||||
to_tunnel(pair);
|
||||
|
||||
if (params.timeout &&
|
||||
if (params.timeout && params.auto_level < 1 &&
|
||||
set_timeout(val->fd, 0)) {
|
||||
return -1;
|
||||
}
|
||||
@ -315,15 +391,7 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
||||
if (!pair->cache) {
|
||||
return 0;
|
||||
}
|
||||
struct sockaddr_ina *addr = (struct sockaddr_ina *)&val->in6;
|
||||
|
||||
if (m == 0) {
|
||||
LOG(LOG_S, "delete ip: m=%d\n", m);
|
||||
} else {
|
||||
INIT_ADDR_STR((*addr));
|
||||
LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m);
|
||||
}
|
||||
return mode_add_get(addr, m);
|
||||
return mode_add_get((struct sockaddr_ina *)&val->in6, m);
|
||||
}
|
||||
|
||||
|
||||
@ -331,7 +399,8 @@ 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)) {
|
||||
if (mod_etype(pool, val, POLLIN) ||
|
||||
mod_etype(pool, val->pair, POLLIN)) {
|
||||
uniperror("mod_etype");
|
||||
return -1;
|
||||
}
|
||||
@ -384,6 +453,7 @@ int on_desync(struct poolhd *pool, struct eval *val,
|
||||
}
|
||||
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) {
|
||||
|
4
extend.h
4
extend.h
@ -19,6 +19,10 @@ int on_desync(struct poolhd *pool, struct eval *val,
|
||||
ssize_t udp_hook(struct eval *val,
|
||||
char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst);
|
||||
|
||||
int on_torst(struct poolhd *pool, struct eval *val);
|
||||
|
||||
int on_fin(struct poolhd *pool, struct eval *val);
|
||||
|
||||
#ifdef __linux__
|
||||
int protect(int conn_fd, const char *path);
|
||||
#else
|
||||
|
47
main.c
47
main.c
@ -23,7 +23,7 @@
|
||||
#define close(fd) closesocket(fd)
|
||||
#endif
|
||||
|
||||
#define VERSION "13.1"
|
||||
#define VERSION "14.1"
|
||||
|
||||
char ip_option[1] = "\0";
|
||||
|
||||
@ -54,13 +54,17 @@ struct params params = {
|
||||
.laddr = {
|
||||
.sin6_family = AF_INET
|
||||
},
|
||||
.debug = 0
|
||||
.debug = 0,
|
||||
.auto_level = 0
|
||||
};
|
||||
|
||||
|
||||
const char help_text[] = {
|
||||
" -i, --ip, <ip> Listening IP, default 0.0.0.0\n"
|
||||
" -p, --port <num> Listening port, default 1080\n"
|
||||
#ifdef __linux__
|
||||
" -E, --transparent Transparent proxy mode\n"
|
||||
#endif
|
||||
" -c, --max-conn <count> Connection count limit, default 512\n"
|
||||
" -N, --no-domain Deny domain resolving\n"
|
||||
" -U, --no-udp Deny UDP association\n"
|
||||
@ -74,6 +78,7 @@ const char help_text[] = {
|
||||
#endif
|
||||
" -A, --auto <t,r,s,n> Try desync params after this option\n"
|
||||
" Detect: torst,redirect,ssl_err,none\n"
|
||||
" -L, --auto-mode <0|1> 1 - handle trigger after several packets\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"
|
||||
@ -116,6 +121,9 @@ const struct option options[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
{"ip", 1, 0, 'i'},
|
||||
{"port", 1, 0, 'p'},
|
||||
#ifdef __linux__
|
||||
{"transparent", 0, 0, 'E'},
|
||||
#endif
|
||||
{"conn-ip", 1, 0, 'I'},
|
||||
{"buf-size", 1, 0, 'b'},
|
||||
{"max-conn", 1, 0, 'c'},
|
||||
@ -125,6 +133,7 @@ const struct option options[] = {
|
||||
{"tfo ", 0, 0, 'F'},
|
||||
#endif
|
||||
{"auto", 1, 0, 'A'},
|
||||
{"auto-mode", 1, 0, 'L'},
|
||||
{"cache-ttl", 1, 0, 'u'},
|
||||
#ifdef TIMEOUT_SUPPORT
|
||||
{"timeout", 1, 0, 'T'},
|
||||
@ -352,6 +361,17 @@ int get_default_ttl()
|
||||
}
|
||||
|
||||
|
||||
bool ipv6_support()
|
||||
{
|
||||
int fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int parse_offset(struct part *part, const char *str)
|
||||
{
|
||||
char *end = 0;
|
||||
@ -464,12 +484,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
params.laddr.sin6_port = htons(1080);
|
||||
if (!ipv6_support()) {
|
||||
params.baddr.sin6_family = AF_INET;
|
||||
}
|
||||
|
||||
int rez;
|
||||
int invalid = 0;
|
||||
|
||||
long val = 0;
|
||||
char *end = 0;
|
||||
bool all_limited = 1;
|
||||
|
||||
struct desync_params *dp = add((void *)¶ms.dp,
|
||||
¶ms.dp_count, sizeof(struct desync_params));
|
||||
@ -492,6 +516,11 @@ int main(int argc, char **argv)
|
||||
case 'U':
|
||||
params.udp = 0;
|
||||
break;
|
||||
#ifdef __linux__
|
||||
case 'E':
|
||||
params.transparent = 1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'h':
|
||||
printf(help_text);
|
||||
@ -550,7 +579,18 @@ int main(int argc, char **argv)
|
||||
params.tfo = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
val = strtol(optarg, &end, 0);
|
||||
if (val < 0 || val > 1 || *end)
|
||||
invalid = 1;
|
||||
else
|
||||
params.auto_level = val;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
if (!(dp->hosts || dp->proto || dp->pf[0] || dp->detect)) {
|
||||
all_limited = 0;
|
||||
}
|
||||
dp = add((void *)¶ms.dp, ¶ms.dp_count,
|
||||
sizeof(struct desync_params));
|
||||
if (!dp) {
|
||||
@ -844,7 +884,7 @@ int main(int argc, char **argv)
|
||||
clear_params();
|
||||
return -1;
|
||||
}
|
||||
if (dp->hosts || dp->proto || dp->pf[0]) {
|
||||
if (all_limited) {
|
||||
dp = add((void *)¶ms.dp,
|
||||
¶ms.dp_count, sizeof(struct desync_params));
|
||||
if (!dp) {
|
||||
@ -868,6 +908,7 @@ int main(int argc, char **argv)
|
||||
clear_params();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int status = run((struct sockaddr_ina *)¶ms.laddr);
|
||||
clear_params();
|
||||
return status;
|
||||
|
@ -15,7 +15,7 @@
|
||||
#endif
|
||||
|
||||
#define ANTOHS(data, i) \
|
||||
(uint16_t)((data[i] << 8) + (uint8_t)data[i + 1])
|
||||
(((uint16_t)data[i] << 8) + (uint8_t)data[i + 1])
|
||||
|
||||
#define SHTONA(data, i, x) \
|
||||
data[i] = (uint8_t)((x) >> 8); \
|
||||
|
19
params.h
19
params.h
@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mpool.h"
|
||||
|
||||
@ -63,11 +64,11 @@ struct desync_params {
|
||||
int ttl;
|
||||
char *ip_options;
|
||||
ssize_t ip_options_len;
|
||||
char md5sig;
|
||||
bool md5sig;
|
||||
struct packet fake_data;
|
||||
int udp_fake_count;
|
||||
int fake_offset;
|
||||
char drop_sack;
|
||||
bool drop_sack;
|
||||
char oob_char[2];
|
||||
|
||||
int parts_n;
|
||||
@ -90,21 +91,23 @@ struct params {
|
||||
int dp_count;
|
||||
struct desync_params *dp;
|
||||
long sfdelay;
|
||||
char wait_send;
|
||||
bool wait_send;
|
||||
int def_ttl;
|
||||
char custom_ttl;
|
||||
bool custom_ttl;
|
||||
|
||||
char tfo;
|
||||
bool tfo;
|
||||
unsigned int timeout;
|
||||
int auto_level;
|
||||
long cache_ttl;
|
||||
char ipv6;
|
||||
char resolve;
|
||||
char udp;
|
||||
bool ipv6;
|
||||
bool resolve;
|
||||
bool udp;
|
||||
int max_open;
|
||||
int debug;
|
||||
size_t bfsize;
|
||||
struct sockaddr_in6 baddr;
|
||||
struct sockaddr_in6 laddr;
|
||||
bool transparent;
|
||||
struct mphdr *mempool;
|
||||
|
||||
char *protect_path;
|
||||
|
108
proxy.c
108
proxy.c
@ -32,9 +32,16 @@
|
||||
#if defined(__linux__) && defined(__GLIBC__)
|
||||
extern int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int);
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
/* For SO_ORIGINAL_DST only (which is 0x50) */
|
||||
#include "linux/netfilter_ipv4.h"
|
||||
#ifndef IP6T_SO_ORIGINAL_DST
|
||||
#define IP6T_SO_ORIGINAL_DST SO_ORIGINAL_DST
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int NOT_EXIT = 1;
|
||||
|
||||
static void on_cancel(int sig) {
|
||||
@ -125,6 +132,7 @@ int resolve(char *host, int len,
|
||||
|
||||
char rchar = host[len];
|
||||
host[len] = '\0';
|
||||
LOG(LOG_S, "resolve: %s\n", host);
|
||||
|
||||
if (getaddrinfo(host, 0, &hints, &res) || !res) {
|
||||
host[len] = rchar;
|
||||
@ -197,6 +205,17 @@ int resp_error(int fd, int e, int flag)
|
||||
}
|
||||
return resp_s5_error(fd, e);
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (params.transparent &&
|
||||
(e == ECONNREFUSED || e == ETIMEDOUT)) {
|
||||
struct linger l = { .l_onoff = 1 };
|
||||
if (setsockopt(fd,
|
||||
SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
|
||||
uniperror("setsockopt SO_LINGER");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -242,7 +261,7 @@ int s5_get_addr(char *buffer, size_t n,
|
||||
struct sockaddr_ina *addr, int type)
|
||||
{
|
||||
if (n < S_SIZE_MIN) {
|
||||
LOG(LOG_E, "ss: request to small\n");
|
||||
LOG(LOG_E, "ss: request too small\n");
|
||||
return -S_ER_GEN;
|
||||
}
|
||||
struct s5_req *r = (struct s5_req *)buffer;
|
||||
@ -393,6 +412,10 @@ int create_conn(struct poolhd *pool,
|
||||
close(sfd);
|
||||
return -1;
|
||||
}
|
||||
if (mod_etype(pool, val, 0) < 0) {
|
||||
uniperror("mod_etype");
|
||||
return -1;
|
||||
}
|
||||
val->pair = pair;
|
||||
pair->pair = val;
|
||||
#ifdef __NetBSD__
|
||||
@ -482,7 +505,7 @@ int udp_associate(struct poolhd *pool,
|
||||
return -1;
|
||||
}
|
||||
struct eval *client = add_event(pool, EV_UDP_TUNNEL, cfd, POLLIN);
|
||||
if (!pair) {
|
||||
if (!client) {
|
||||
del_event(pool, pair);
|
||||
close(cfd);
|
||||
return -1;
|
||||
@ -519,6 +542,38 @@ int udp_associate(struct poolhd *pool,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static inline int transp_conn(struct poolhd *pool, struct eval *val)
|
||||
{
|
||||
struct sockaddr_ina remote, self;
|
||||
socklen_t rlen = sizeof(remote), slen = sizeof(self);
|
||||
if (getsockopt(val->fd, IPPROTO_IP,
|
||||
SO_ORIGINAL_DST, &remote, &rlen) != 0)
|
||||
{
|
||||
if (getsockopt(val->fd, IPPROTO_IPV6,
|
||||
IP6T_SO_ORIGINAL_DST, &remote, &rlen) != 0) {
|
||||
uniperror("getsockopt SO_ORIGINAL_DST");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (getsockname(val->fd, &self.sa, &slen) < 0) {
|
||||
uniperror("getsockname");
|
||||
return -1;
|
||||
}
|
||||
if (self.sa.sa_family == remote.sa.sa_family &&
|
||||
self.in.sin_port == remote.in.sin_port &&
|
||||
addr_equ(&self, &remote)) {
|
||||
LOG(LOG_E, "connect to self, ignore\n");
|
||||
return -1;
|
||||
}
|
||||
int error = connect_hook(pool, val, &remote, EV_CONNECT);
|
||||
if (error) {
|
||||
uniperror("connect_hook");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int on_accept(struct poolhd *pool, struct eval *val)
|
||||
{
|
||||
@ -565,6 +620,12 @@ static inline int on_accept(struct poolhd *pool, struct eval *val)
|
||||
continue;
|
||||
}
|
||||
rval->in6 = client.in6;
|
||||
#ifdef __linux__
|
||||
if (params.transparent && transp_conn(pool, rval) < 0) {
|
||||
del_event(pool, rval);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -614,11 +675,30 @@ int on_tunnel(struct poolhd *pool, struct eval *val,
|
||||
if (n < 0 && get_e() == EAGAIN) {
|
||||
break;
|
||||
}
|
||||
if (n < 1) {
|
||||
if (n) uniperror("recv");
|
||||
if (n == 0) {
|
||||
if (val->flag != FLAG_CONN)
|
||||
val = val->pair;
|
||||
on_fin(pool, val);
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
val->recv_count += n;
|
||||
if (!val->last_round) {
|
||||
val->round_count++;
|
||||
val->last_round = 1;
|
||||
pair->last_round = 0;
|
||||
}
|
||||
|
||||
ssize_t sn = send(pair->fd, buffer, n, 0);
|
||||
if (sn != n) {
|
||||
@ -753,7 +833,7 @@ static inline int on_request(struct poolhd *pool, struct eval *val,
|
||||
return 0;
|
||||
}
|
||||
if (n < S_SIZE_MIN) {
|
||||
LOG(LOG_E, "ss: request to small (%zd)\n", n);
|
||||
LOG(LOG_E, "ss: request too small (%zd)\n", n);
|
||||
return -1;
|
||||
}
|
||||
struct s5_req *r = (struct s5_req *)buffer;
|
||||
@ -821,7 +901,8 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mod_etype(pool, val, POLLIN)) {
|
||||
if (mod_etype(pool, val, POLLIN) ||
|
||||
mod_etype(pool, val->pair, POLLIN)) {
|
||||
uniperror("mod_etype");
|
||||
return -1;
|
||||
}
|
||||
@ -839,23 +920,24 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
|
||||
|
||||
void close_conn(struct poolhd *pool, struct eval *val)
|
||||
{
|
||||
LOG(LOG_S, "close: fds=%d,%d\n", val->fd, val->pair ? val->pair->fd : -1);
|
||||
LOG(LOG_S, "close: fds=%d,%d, recv: %zd,%zd, rounds: %d,%d\n",
|
||||
val->fd, val->pair ? val->pair->fd : -1,
|
||||
val->recv_count, val->pair ? val->pair->recv_count : 0,
|
||||
val->round_count, val->pair ? val->pair->round_count : 0);
|
||||
del_event(pool, val);
|
||||
}
|
||||
|
||||
|
||||
int event_loop(int srvfd)
|
||||
int event_loop(int srvfd)
|
||||
{
|
||||
size_t bfsize = params.bfsize;
|
||||
|
||||
struct poolhd *pool = init_pool(params.max_open * 2 + 1);
|
||||
if (!pool) {
|
||||
uniperror("init pool");
|
||||
close(srvfd);
|
||||
return -1;
|
||||
}
|
||||
if (!add_event(pool, EV_ACCEPT, srvfd, POLLIN)) {
|
||||
uniperror("add event");
|
||||
destroy_pool(pool);
|
||||
close(srvfd);
|
||||
return -1;
|
||||
@ -880,7 +962,7 @@ int event_loop(int srvfd)
|
||||
}
|
||||
assert(val->type >= 0
|
||||
&& val->type < sizeof(eid_name)/sizeof(*eid_name));
|
||||
LOG(LOG_L, "new event: fd: %d, evt: %s, mod_iter: %d\n", val->fd, eid_name[val->type], val->mod_iter);
|
||||
LOG(LOG_L, "new event: fd: %d, evt: %s, mod_iter: %llu\n", val->fd, eid_name[val->type], val->mod_iter);
|
||||
|
||||
switch (val->type) {
|
||||
case EV_ACCEPT:
|
||||
@ -974,6 +1056,7 @@ int run(struct sockaddr_ina *srv)
|
||||
uniperror("signal SIGPIPE!");
|
||||
#endif
|
||||
signal(SIGINT, on_cancel);
|
||||
signal(SIGTERM, on_cancel);
|
||||
|
||||
int fd = listen_socket(srv);
|
||||
if (fd < 0) {
|
||||
@ -981,4 +1064,3 @@ int run(struct sockaddr_ina *srv)
|
||||
}
|
||||
return event_loop(fd);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user