Merge branch 'hufrea:main' into cmake

This commit is contained in:
Nikolay Raspopov 2024-10-08 20:17:44 +03:00 committed by GitHub
commit f265ab4b24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 399 additions and 121 deletions

View File

@ -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)

View File

@ -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
View File

@ -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;

View File

@ -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);

View File

@ -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
View 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
View 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
View 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

View File

@ -11,6 +11,8 @@
#include <android/log.h>
#endif
#include "params.h"
#ifdef _WIN32
#define get_e() \
unie(WSAGetLastError())

180
extend.c
View File

@ -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 = &params.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 = &params.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 = &params.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) {

View File

@ -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
View File

@ -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 *)&params.dp,
&params.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 *)&params.dp, &params.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 *)&params.dp,
&params.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 *)&params.laddr);
clear_params();
return status;

View File

@ -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); \

View File

@ -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
View File

@ -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);
}