mirror of
https://github.com/hufrea/byedpi.git
synced 2024-12-22 14:25:44 +00:00
UDP, --proto, dst custom port
This commit is contained in:
parent
f9fa5a14f6
commit
a48a2e87a3
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
|||||||
TARGET = ciadpi
|
TARGET = ciadpi
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=c99 -O2 -D_XOPEN_SOURCE=500
|
CFLAGS += -std=c99 -O2 -D_XOPEN_SOURCE=500
|
||||||
SOURCES = packets.c main.c conev.c proxy.c desync.c mpool.c
|
SOURCES = packets.c main.c conev.c proxy.c desync.c mpool.c extend.c
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(CC) $(CFLAGS) $(SOURCES) -I . -o $(TARGET)
|
$(CC) $(CFLAGS) $(SOURCES) -I . -o $(TARGET)
|
||||||
|
5
conev.h
5
conev.h
@ -1,3 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
@ -35,6 +36,7 @@ enum eid {
|
|||||||
EV_IGNORE,
|
EV_IGNORE,
|
||||||
EV_TUNNEL,
|
EV_TUNNEL,
|
||||||
EV_PRE_TUNNEL,
|
EV_PRE_TUNNEL,
|
||||||
|
EV_UDP_TUNNEL,
|
||||||
EV_DESYNC
|
EV_DESYNC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ enum eid {
|
|||||||
#define FLAG_S5 2
|
#define FLAG_S5 2
|
||||||
#define FLAG_CONN 4
|
#define FLAG_CONN 4
|
||||||
|
|
||||||
#ifndef CONEV_H
|
#ifdef EID_STR
|
||||||
char *eid_name[] = {
|
char *eid_name[] = {
|
||||||
"EV_ACCEPT",
|
"EV_ACCEPT",
|
||||||
"EV_REQUEST",
|
"EV_REQUEST",
|
||||||
@ -50,6 +52,7 @@ char *eid_name[] = {
|
|||||||
"EV_IGNORE",
|
"EV_IGNORE",
|
||||||
"EV_TUNNEL",
|
"EV_TUNNEL",
|
||||||
"EV_PRE_TUNNEL",
|
"EV_PRE_TUNNEL",
|
||||||
|
"EV_UDP_TUNNEL",
|
||||||
"EV_DESYNC"
|
"EV_DESYNC"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
21
desync.c
21
desync.c
@ -131,7 +131,13 @@ ssize_t send_fake(int sfd, char *buffer,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http;
|
struct packet pkt;
|
||||||
|
if (opt->fake_data.data) {
|
||||||
|
pkt = opt->fake_data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pkt = cnt != IS_HTTP ? fake_tls : fake_http;
|
||||||
|
}
|
||||||
size_t psz = pkt.size;
|
size_t psz = pkt.size;
|
||||||
|
|
||||||
int ffd = memfd_create("name", O_RDWR);
|
int ffd = memfd_create("name", O_RDWR);
|
||||||
@ -218,7 +224,13 @@ ssize_t send_fake(int sfd, char *buffer,
|
|||||||
ssize_t send_fake(int sfd, char *buffer,
|
ssize_t send_fake(int sfd, char *buffer,
|
||||||
int cnt, long pos, int fa, struct desync_params *opt)
|
int cnt, long pos, int fa, struct desync_params *opt)
|
||||||
{
|
{
|
||||||
struct packet pkt = cnt != IS_HTTP ? fake_tls : fake_http;
|
struct packet pkt;
|
||||||
|
if (opt->fake_data.data) {
|
||||||
|
pkt = opt->fake_data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pkt = cnt != IS_HTTP ? fake_tls : fake_http;
|
||||||
|
}
|
||||||
size_t psz = pkt.size;
|
size_t psz = pkt.size;
|
||||||
|
|
||||||
char path[MAX_PATH + 1];
|
char path[MAX_PATH + 1];
|
||||||
@ -439,10 +451,7 @@ ssize_t desync(int sfd, char *buffer, size_t bfsize,
|
|||||||
// desync
|
// desync
|
||||||
long lp = offset;
|
long lp = offset;
|
||||||
|
|
||||||
if (!type && params.de_known) {
|
for (int i = 0; i < dp.parts_n; i++) {
|
||||||
// cancel
|
|
||||||
}
|
|
||||||
else for (int i = 0; i < dp.parts_n; i++) {
|
|
||||||
struct part part = dp.parts[i];
|
struct part part = dp.parts[i];
|
||||||
|
|
||||||
// change pos
|
// change pos
|
||||||
|
413
extend.c
Normal file
413
extend.c
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#ifndef TCP_MAXRT
|
||||||
|
#define TCP_MAXRT 5
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <proxy.h>
|
||||||
|
#include <error.h>
|
||||||
|
#include <params.h>
|
||||||
|
|
||||||
|
#include <desync.h>
|
||||||
|
#include <packets.h>
|
||||||
|
|
||||||
|
|
||||||
|
int set_timeout(int fd, unsigned int s)
|
||||||
|
{
|
||||||
|
#ifdef __linux__
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP,
|
||||||
|
TCP_USER_TIMEOUT, (char *)&s, sizeof(s))) {
|
||||||
|
uniperror("setsockopt TCP_USER_TIMEOUT");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP,
|
||||||
|
TCP_MAXRT, (char *)&s, sizeof(s))) {
|
||||||
|
uniperror("setsockopt TCP_MAXRT");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mode_add_get(struct sockaddr_ina *dst, int m)
|
||||||
|
{
|
||||||
|
// m < 0: get, m > 0: set, m == 0: delete
|
||||||
|
time_t t;
|
||||||
|
struct elem *val;
|
||||||
|
char *str = (char *)&dst->in;
|
||||||
|
int len = sizeof(dst->sa.sa_family);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (m == 0) {
|
||||||
|
mem_delete(params.mempool, str, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (m > 0) {
|
||||||
|
time(&t);
|
||||||
|
val = mem_add(params.mempool, str, len);
|
||||||
|
if (!val) {
|
||||||
|
uniperror("mem_add");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->m = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ext_connect(struct poolhd *pool, struct eval *val,
|
||||||
|
struct sockaddr_ina *dst, int next, int m)
|
||||||
|
{
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
if (dp->to_ip == 2) {
|
||||||
|
struct sockaddr_ina addr = { .in6 = dp->addr };
|
||||||
|
if (!addr.in.sin_port) {
|
||||||
|
addr.in.sin_port = dst->in.sin_port;
|
||||||
|
}
|
||||||
|
return create_conn(pool, val, &addr, next);
|
||||||
|
}
|
||||||
|
return create_conn(pool, val, dst, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int connect_hook(struct poolhd *pool, struct eval *val,
|
||||||
|
struct sockaddr_ina *dst, int next)
|
||||||
|
{
|
||||||
|
int m = mode_add_get(dst, -1);
|
||||||
|
val->cache = (m == 0);
|
||||||
|
val->attempt = m < 0 ? 0 : m;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return ext_connect(pool, val, dst, next, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int reconnect(struct poolhd *pool, struct eval *val, int m)
|
||||||
|
{
|
||||||
|
struct eval *client = val->pair;
|
||||||
|
|
||||||
|
if (ext_connect(pool, client,
|
||||||
|
(struct sockaddr_ina *)&val->in6, EV_DESYNC, m)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->pair = 0;
|
||||||
|
del_event(pool, val);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool check_proto_tcp(int proto, struct eval *val)
|
||||||
|
{
|
||||||
|
if ((proto & IS_HTTP) &&
|
||||||
|
is_http(val->buff.data, val->buff.size)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((proto & IS_HTTPS) &&
|
||||||
|
is_tls_chello(val->buff.data, val->buff.size)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool check_proto_udp(int proto, char *buffer, size_t n)
|
||||||
|
{
|
||||||
|
if ((proto & IS_QUIC) &&
|
||||||
|
is_quic_inital(buffer, n)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((proto & IS_DNS) &&
|
||||||
|
is_dns_req(buffer, n)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 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 = ¶ms.dp[m];
|
||||||
|
if (!(dp->detect & DETECT_TORST)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((!dp->hosts || check_host(dp->hosts, val->pair)) &&
|
||||||
|
(!dp->proto || check_proto_tcp(dp->proto, val))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m >= params.dp_count) {
|
||||||
|
mode_add_get(
|
||||||
|
(struct sockaddr_ina *)&val->in6, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return reconnect(pool, val, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int on_response(struct poolhd *pool, struct eval *val,
|
||||||
|
char *resp, ssize_t sn)
|
||||||
|
{
|
||||||
|
int m = val->pair->attempt + 1;
|
||||||
|
|
||||||
|
char *req = val->pair->buff.data;
|
||||||
|
ssize_t qn = val->pair->buff.size;
|
||||||
|
|
||||||
|
for (; m < params.dp_count; m++) {
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
|
||||||
|
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)) &&
|
||||||
|
(!dp->proto || check_proto_tcp(dp->proto, val))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m < params.dp_count) {
|
||||||
|
return reconnect(pool, val, m);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize, int out)
|
||||||
|
{
|
||||||
|
if (out) {
|
||||||
|
return on_tunnel(pool, val, buffer, bfsize, out);
|
||||||
|
}
|
||||||
|
ssize_t n = recv(val->fd, buffer, bfsize, 0);
|
||||||
|
if (n < 1) {
|
||||||
|
uniperror("recv");
|
||||||
|
switch (get_e()) {
|
||||||
|
case ECONNRESET:
|
||||||
|
case ETIMEDOUT:
|
||||||
|
break;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
return on_torst(pool, val);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (on_response(pool, val, buffer, n) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
struct eval *pair = val->pair;
|
||||||
|
|
||||||
|
ssize_t sn = send(pair->fd, buffer, n, 0);
|
||||||
|
if (n != sn) {
|
||||||
|
uniperror("send");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->type = EV_TUNNEL;
|
||||||
|
pair->type = EV_TUNNEL;
|
||||||
|
|
||||||
|
free(pair->buff.data);
|
||||||
|
pair->buff.data = 0;
|
||||||
|
pair->buff.size = 0;
|
||||||
|
|
||||||
|
if (params.timeout &&
|
||||||
|
set_timeout(val->fd, 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int m = pair->attempt;
|
||||||
|
|
||||||
|
if (!pair->cache) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (m == 0) {
|
||||||
|
LOG(LOG_S, "delete ip: m=%d\n", m);
|
||||||
|
} else {
|
||||||
|
LOG(LOG_S, "save ip: m=%d\n", m);
|
||||||
|
}
|
||||||
|
return mode_add_get(
|
||||||
|
(struct sockaddr_ina *)&val->in6, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int on_desync(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize)
|
||||||
|
{
|
||||||
|
if (val->flag == FLAG_CONN) {
|
||||||
|
if (mod_etype(pool, val, POLLOUT, 0)) {
|
||||||
|
uniperror("mod_etype");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val = val->pair;
|
||||||
|
}
|
||||||
|
ssize_t n;
|
||||||
|
int m = val->attempt;
|
||||||
|
LOG((m ? LOG_S : LOG_L), "desync params index: %d\n", m);
|
||||||
|
|
||||||
|
if (!val->buff.data) {
|
||||||
|
n = recv(val->fd, buffer, bfsize, 0);
|
||||||
|
if (n <= 0) {
|
||||||
|
if (n) uniperror("recv data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->buff.size = n;
|
||||||
|
val->recv_count += n;
|
||||||
|
|
||||||
|
if (!(val->buff.data = malloc(n))) {
|
||||||
|
uniperror("malloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(val->buff.data, buffer, n);
|
||||||
|
|
||||||
|
if (!m) for (; m < params.dp_count; m++) {
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
if (!dp->detect &&
|
||||||
|
(!dp->hosts || check_host(dp->hosts, val)) &&
|
||||||
|
(!dp->proto || check_proto_tcp(dp->proto, 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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (sn < n) {
|
||||||
|
val->buff.offset = sn;
|
||||||
|
if (mod_etype(pool, val->pair, POLLOUT, 1)) {
|
||||||
|
uniperror("mod_etype");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->pair->type = EV_DESYNC;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
val->type = EV_TUNNEL;
|
||||||
|
val->pair->type = EV_PRE_TUNNEL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t udp_hook(struct eval *val,
|
||||||
|
char *buffer, size_t n, struct sockaddr_ina *dst)
|
||||||
|
{
|
||||||
|
int m = val->attempt;
|
||||||
|
struct desync_params *dp = ¶ms.dp[m];
|
||||||
|
|
||||||
|
if (val->flag != FLAG_CONN) {
|
||||||
|
if (!m) for (; m < params.dp_count; m++) {
|
||||||
|
dp = ¶ms.dp[m];
|
||||||
|
if ((!dp->proto || check_proto_udp(dp->proto, buffer, n))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m >= params.dp_count) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->attempt = m;
|
||||||
|
val->flag = FLAG_CONN;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_ina addr;
|
||||||
|
if (dp->to_ip) {
|
||||||
|
addr.in6 = dp->addr;
|
||||||
|
if (dst->sa.sa_family == AF_INET6) {
|
||||||
|
map_fix(&addr, 6);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
map_fix(&addr, 0);
|
||||||
|
}
|
||||||
|
if (!addr.in.sin_port) {
|
||||||
|
addr.in.sin_port = dst->in.sin_port;
|
||||||
|
}
|
||||||
|
dst = &addr;
|
||||||
|
}
|
||||||
|
return sendto(val->fd, buffer, n, 0, &dst->sa, sizeof(*dst));
|
||||||
|
}
|
11
extend.h
Normal file
11
extend.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
int connect_hook(struct poolhd *pool, struct eval *val,
|
||||||
|
struct sockaddr_ina *dst, int next);
|
||||||
|
|
||||||
|
int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize, int out);
|
||||||
|
|
||||||
|
int on_desync(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize);
|
||||||
|
|
||||||
|
ssize_t udp_hook(struct eval *val,
|
||||||
|
char *buffer, size_t n, struct sockaddr_ina *dst);
|
124
main.c
124
main.c
@ -49,6 +49,7 @@ struct params params = {
|
|||||||
.cache_ttl = 100800,
|
.cache_ttl = 100800,
|
||||||
.ipv6 = 1,
|
.ipv6 = 1,
|
||||||
.resolve = 1,
|
.resolve = 1,
|
||||||
|
.udp = 1,
|
||||||
.max_open = 512,
|
.max_open = 512,
|
||||||
.bfsize = 16384,
|
.bfsize = 16384,
|
||||||
.baddr = {
|
.baddr = {
|
||||||
@ -63,24 +64,25 @@ const char help_text[] = {
|
|||||||
" -p, --port <num> Listening port, default 1080\n"
|
" -p, --port <num> Listening port, default 1080\n"
|
||||||
" -c, --max-conn <count> Connection count limit, default 512\n"
|
" -c, --max-conn <count> Connection count limit, default 512\n"
|
||||||
" -N, --no-domain Deny domain resolving\n"
|
" -N, --no-domain Deny domain resolving\n"
|
||||||
|
" -U, --no-udp Deny UDP association\n"
|
||||||
" -I --conn-ip <ip> Connection binded IP, default ::\n"
|
" -I --conn-ip <ip> Connection binded IP, default ::\n"
|
||||||
" -b, --buf-size <size> Buffer size, default 16384\n"
|
" -b, --buf-size <size> Buffer size, default 16384\n"
|
||||||
" -x, --debug <level> Print logs, 0, 1 or 2\n"
|
" -x, --debug <level> Print logs, 0, 1 or 2\n"
|
||||||
" -g, --def-ttl <num> TTL for all outgoing connections\n"
|
" -g, --def-ttl <num> TTL for all outgoing connections\n"
|
||||||
// desync options
|
// desync options
|
||||||
" -K, --desync-known Desync only HTTP and TLS with SNI\n"
|
|
||||||
#ifdef TCP_FASTOPEN_CONNECT
|
#ifdef TCP_FASTOPEN_CONNECT
|
||||||
" -F, --tfo Enable TCP Fast Open\n"
|
" -F, --tfo Enable TCP Fast Open\n"
|
||||||
#endif
|
#endif
|
||||||
" -L, --late-conn Waiting for request before connecting\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"
|
" -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"
|
" Detect: torst,redirect,cl_err,sid_inv,alert,none\n"
|
||||||
" -u, --cache-ttl <sec> Lifetime of cached desync params for IP\n"
|
" -u, --cache-ttl <sec> Lifetime of cached desync params for IP\n"
|
||||||
#ifdef TIMEOUT_SUPPORT
|
#ifdef TIMEOUT_SUPPORT
|
||||||
" -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n"
|
" -T, --timeout <sec> Timeout waiting for response, after which trigger auto\n"
|
||||||
#endif
|
#endif
|
||||||
|
" -K, --proto[=t,h,d,q] Protocol whitelist: tls,http,dns,quic\n"
|
||||||
" -H, --hosts <file|:str> Hosts whitelist\n"
|
" -H, --hosts <file|:str> Hosts whitelist\n"
|
||||||
" -D, --dst <addr> Custom destination IP\n"
|
" -D, --dst <ip[:port]> Custom destination IP\n"
|
||||||
" -s, --split <n[+s]> Split packet at n\n"
|
" -s, --split <n[+s]> Split packet at n\n"
|
||||||
" +s - add SNI offset\n"
|
" +s - add SNI offset\n"
|
||||||
" +h - add HTTP Host offset\n"
|
" +h - add HTTP Host offset\n"
|
||||||
@ -93,8 +95,7 @@ const char help_text[] = {
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
" -S, --md5sig Add MD5 Signature option for fake packets\n"
|
" -S, --md5sig Add MD5 Signature option for fake packets\n"
|
||||||
#endif
|
#endif
|
||||||
" -l, --fake-tls <f|:str>\n"
|
" -l, --fake-data <f|:str> Set custom fake packet\n"
|
||||||
" -j, --fake-http <f|:str> Set custom fake packet\n"
|
|
||||||
" -n, --tls-sni <str> Change SNI in fake ClientHello\n"
|
" -n, --tls-sni <str> Change SNI in fake ClientHello\n"
|
||||||
#endif
|
#endif
|
||||||
" -e, --oob-data <f|:str> Set custom OOB data, filename or :string\n"
|
" -e, --oob-data <f|:str> Set custom OOB data, filename or :string\n"
|
||||||
@ -106,6 +107,7 @@ const char help_text[] = {
|
|||||||
const struct option options[] = {
|
const struct option options[] = {
|
||||||
{"no-domain", 0, 0, 'N'},
|
{"no-domain", 0, 0, 'N'},
|
||||||
{"no-ipv6", 0, 0, 'X'},
|
{"no-ipv6", 0, 0, 'X'},
|
||||||
|
{"no-udp", 0, 0, 'U'},
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
{"ip", 1, 0, 'i'},
|
{"ip", 1, 0, 'i'},
|
||||||
@ -115,7 +117,6 @@ const struct option options[] = {
|
|||||||
{"max-conn", 1, 0, 'c'},
|
{"max-conn", 1, 0, 'c'},
|
||||||
{"debug", 1, 0, 'x'},
|
{"debug", 1, 0, 'x'},
|
||||||
|
|
||||||
{"desync-known ", 0, 0, 'K'},
|
|
||||||
#ifdef TCP_FASTOPEN_CONNECT
|
#ifdef TCP_FASTOPEN_CONNECT
|
||||||
{"tfo ", 0, 0, 'F'},
|
{"tfo ", 0, 0, 'F'},
|
||||||
#endif
|
#endif
|
||||||
@ -125,6 +126,7 @@ const struct option options[] = {
|
|||||||
#ifdef TIMEOUT_SUPPORT
|
#ifdef TIMEOUT_SUPPORT
|
||||||
{"timeout", 1, 0, 'T'},
|
{"timeout", 1, 0, 'T'},
|
||||||
#endif
|
#endif
|
||||||
|
{"proto", 2, 0, 'K'},
|
||||||
{"hosts", 1, 0, 'H'},
|
{"hosts", 1, 0, 'H'},
|
||||||
{"dst", 1, 0, 'D'},
|
{"dst", 1, 0, 'D'},
|
||||||
{"split", 1, 0, 's'},
|
{"split", 1, 0, 's'},
|
||||||
@ -137,8 +139,7 @@ const struct option options[] = {
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
{"md5sig", 0, 0, 'S'},
|
{"md5sig", 0, 0, 'S'},
|
||||||
#endif
|
#endif
|
||||||
{"fake-tls", 1, 0, 'l'},
|
{"fake-data", 1, 0, 'l'},
|
||||||
{"fake-http", 1, 0, 'j'},
|
|
||||||
{"tls-sni", 1, 0, 'n'},
|
{"tls-sni", 1, 0, 'n'},
|
||||||
#endif
|
#endif
|
||||||
{"oob-data", 1, 0, 'e'},
|
{"oob-data", 1, 0, 'e'},
|
||||||
@ -250,7 +251,7 @@ struct mphdr *parse_hosts(char *buffer, size_t size)
|
|||||||
char *e = buffer, *s = buffer;
|
char *e = buffer, *s = buffer;
|
||||||
|
|
||||||
for (; e <= end; e++) {
|
for (; e <= end; e++) {
|
||||||
if (*e != ' ' && *e != '\n' && e != end) {
|
if (*e != ' ' && *e != '\n' && *e != '\r' && e != end) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (s == e) {
|
if (s == e) {
|
||||||
@ -288,6 +289,46 @@ int get_addr(const char *str, struct sockaddr_ina *addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_addr_with_port(const char *str, struct sockaddr_ina *addr)
|
||||||
|
{
|
||||||
|
uint16_t port = 0;
|
||||||
|
char *s = (char *)str, *e = 0;
|
||||||
|
char *end = 0, *p = s;
|
||||||
|
|
||||||
|
if (*str == '[') {
|
||||||
|
e = strchr(str, ']');
|
||||||
|
if (!e) return -1;
|
||||||
|
s++; p = e + 1;
|
||||||
|
}
|
||||||
|
p = strchr(p, ':');
|
||||||
|
if (p) {
|
||||||
|
long val = strtol(p + 1, &end, 0);
|
||||||
|
if (val <= 0 || val > 0xffff || *end)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
port = htons(val);
|
||||||
|
if (!e) e = p;
|
||||||
|
}
|
||||||
|
if (!e) {
|
||||||
|
e = strchr(s, 0);
|
||||||
|
}
|
||||||
|
if ((e - s) < 7) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char str_ip[(e - s) + 1];
|
||||||
|
memcpy(str_ip, s, e - s);
|
||||||
|
str_ip[e - s] = 0;
|
||||||
|
|
||||||
|
if (get_addr(str_ip, addr) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (port) {
|
||||||
|
addr->in6.sin6_port = port;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int get_default_ttl()
|
int get_default_ttl()
|
||||||
{
|
{
|
||||||
int orig_ttl = -1, fd;
|
int orig_ttl = -1, fd;
|
||||||
@ -368,18 +409,14 @@ void clear_params(void)
|
|||||||
free(s.parts);
|
free(s.parts);
|
||||||
s.parts = 0;
|
s.parts = 0;
|
||||||
}
|
}
|
||||||
|
if (s.fake_data.data) {
|
||||||
|
FREE(s.fake_data.data, s.fake_data.size);
|
||||||
|
s.fake_data.data = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(params.dp);
|
free(params.dp);
|
||||||
params.dp = 0;
|
params.dp = 0;
|
||||||
}
|
}
|
||||||
if (fake_tls.data != tls_data) {
|
|
||||||
FREE(fake_tls.data, fake_tls.size);
|
|
||||||
fake_tls.data = tls_data;
|
|
||||||
}
|
|
||||||
if (fake_http.data != http_data) {
|
|
||||||
FREE(fake_http.data, fake_http.size);
|
|
||||||
fake_http.data = http_data;
|
|
||||||
}
|
|
||||||
if (oob_data.data != oob_char) {
|
if (oob_data.data != oob_char) {
|
||||||
FREE(oob_data.data, oob_data.size);
|
FREE(oob_data.data, oob_data.size);
|
||||||
oob_data.data = oob_char;
|
oob_data.data = oob_char;
|
||||||
@ -444,6 +481,10 @@ int main(int argc, char **argv)
|
|||||||
case 'X':
|
case 'X':
|
||||||
params.ipv6 = 0;
|
params.ipv6 = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'U':
|
||||||
|
params.udp = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
printf(help_text);
|
printf(help_text);
|
||||||
clear_params();
|
clear_params();
|
||||||
@ -501,10 +542,6 @@ int main(int argc, char **argv)
|
|||||||
params.late_conn = 1;
|
params.late_conn = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'K':
|
|
||||||
params.de_known = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
params.tfo = 1;
|
params.tfo = 1;
|
||||||
break;
|
break;
|
||||||
@ -570,6 +607,35 @@ int main(int argc, char **argv)
|
|||||||
params.timeout = val;
|
params.timeout = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'K':
|
||||||
|
if (!optarg) {
|
||||||
|
dp->proto |= 0xffffffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end = optarg;
|
||||||
|
while (end && !invalid) {
|
||||||
|
switch (*end) {
|
||||||
|
case 't':
|
||||||
|
dp->proto |= IS_HTTPS;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
dp->proto |= IS_HTTP;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
dp->proto |= IS_DNS;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
dp->proto |= IS_QUIC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
invalid = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
end = strchr(end, ',');
|
||||||
|
if (end) end++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'H':;
|
case 'H':;
|
||||||
char *data = ftob(optarg, &val);
|
char *data = ftob(optarg, &val);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@ -585,7 +651,7 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
if (get_addr(optarg, (struct sockaddr_ina *)&dp->addr) < 0)
|
if (get_addr_with_port(optarg, (struct sockaddr_ina *)&dp->addr) < 0)
|
||||||
invalid = 1;
|
invalid = 1;
|
||||||
else
|
else
|
||||||
dp->to_ip = 2;
|
dp->to_ip = 2;
|
||||||
@ -652,16 +718,8 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
fake_tls.data = ftob(optarg, &fake_tls.size);
|
dp->fake_data.data = ftob(optarg, &dp->fake_data.size);
|
||||||
if (!fake_tls.data) {
|
if (!dp->fake_data.data) {
|
||||||
uniperror("read/parse");
|
|
||||||
invalid = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'j':
|
|
||||||
fake_http.data = ftob(optarg, &fake_http.size);
|
|
||||||
if (!fake_http.data) {
|
|
||||||
uniperror("read/parse");
|
uniperror("read/parse");
|
||||||
invalid = 1;
|
invalid = 1;
|
||||||
}
|
}
|
||||||
@ -750,7 +808,7 @@ int main(int argc, char **argv)
|
|||||||
clear_params();
|
clear_params();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (dp->hosts) {
|
if (dp->hosts || dp->proto) {
|
||||||
dp = add((void *)¶ms.dp,
|
dp = add((void *)¶ms.dp,
|
||||||
¶ms.dp_count, sizeof(struct desync_params));
|
¶ms.dp_count, sizeof(struct desync_params));
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
|
2
mpool.c
2
mpool.c
@ -97,4 +97,4 @@ void mem_destroy(struct mphdr *hdr)
|
|||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
free(hdr);
|
free(hdr);
|
||||||
}
|
}
|
||||||
|
27
packets.c
27
packets.c
@ -141,9 +141,17 @@ int change_tls_sni(const char *host, char *buffer, size_t bsize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool is_tls_chello(char *buffer, size_t bsize)
|
||||||
|
{
|
||||||
|
return (bsize > 5 &&
|
||||||
|
ANTOHS(buffer, 0) == 0x1603 &&
|
||||||
|
buffer[5] == 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int parse_tls(char *buffer, size_t bsize, char **hs)
|
int parse_tls(char *buffer, size_t bsize, char **hs)
|
||||||
{
|
{
|
||||||
if (ANTOHS(buffer, 0) != 0x1603) {
|
if (!is_tls_chello(buffer, bsize)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t sni_offs = find_tls_ext_offset(0x00, buffer, bsize);
|
size_t sni_offs = find_tls_ext_offset(0x00, buffer, bsize);
|
||||||
@ -312,7 +320,7 @@ bool neq_tls_sid(char *req, size_t qn, char *resp, size_t sn)
|
|||||||
if (qn < 75 || sn < 75) {
|
if (qn < 75 || sn < 75) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (ANTOHS(req, 0) != 0x1603
|
if (!is_tls_chello(req, qn)
|
||||||
|| ANTOHS(resp, 0) != 0x1603) {
|
|| ANTOHS(resp, 0) != 0x1603) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -330,6 +338,21 @@ bool is_tls_alert(char *resp, size_t sn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool is_dns_req(char *buffer, size_t n)
|
||||||
|
{
|
||||||
|
if (n < 12) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return !memcmp(buffer + 2, "\1\0\0\1\0\0\0\0\0\0", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool is_quic_inital(char *buffer, size_t bsize)
|
||||||
|
{
|
||||||
|
return (bsize > 64 && (buffer[0] & 0xc0) == 0xc0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int mod_http(char *buffer, size_t bsize, int m)
|
int mod_http(char *buffer, size_t bsize, int m)
|
||||||
{
|
{
|
||||||
char *host = 0, *par;
|
char *host = 0, *par;
|
||||||
|
10
packets.h
10
packets.h
@ -6,6 +6,8 @@
|
|||||||
#define IS_UNKNOWN 0
|
#define IS_UNKNOWN 0
|
||||||
#define IS_HTTP 1
|
#define IS_HTTP 1
|
||||||
#define IS_HTTPS 2
|
#define IS_HTTPS 2
|
||||||
|
#define IS_QUIC 4
|
||||||
|
#define IS_DNS 8
|
||||||
|
|
||||||
#define MH_HMIX 1
|
#define MH_HMIX 1
|
||||||
#define MH_SPACE 2
|
#define MH_SPACE 2
|
||||||
@ -16,8 +18,12 @@ extern char http_data[43];
|
|||||||
|
|
||||||
int change_tls_sni(const char *host, char *buffer, size_t bsize);
|
int change_tls_sni(const char *host, char *buffer, size_t bsize);
|
||||||
|
|
||||||
|
bool is_tls_chello(char *buffer, size_t bsize);
|
||||||
|
|
||||||
int parse_tls(char *buffer, size_t bsize, char **hs);
|
int parse_tls(char *buffer, size_t bsize, char **hs);
|
||||||
|
|
||||||
|
bool is_http(char *buffer, size_t bsize);
|
||||||
|
|
||||||
int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port);
|
int parse_http(char *buffer, size_t bsize, char **hs, uint16_t *port);
|
||||||
|
|
||||||
int mod_http(char *buffer, size_t bsize, int m);
|
int mod_http(char *buffer, size_t bsize, int m);
|
||||||
@ -31,3 +37,7 @@ bool neq_tls_sid(char *req, size_t qn, char *resp, size_t sn);
|
|||||||
bool is_tls_alert(char *resp, size_t sn);
|
bool is_tls_alert(char *resp, size_t sn);
|
||||||
|
|
||||||
int part_tls(char *buffer, size_t bsize, ssize_t n, long pos);
|
int part_tls(char *buffer, size_t bsize, ssize_t n, long pos);
|
||||||
|
|
||||||
|
bool is_dns_req(char *buffer, size_t n);
|
||||||
|
|
||||||
|
bool is_quic_inital(char *buffer, size_t bsize);
|
||||||
|
16
params.h
16
params.h
@ -45,16 +45,26 @@ struct part {
|
|||||||
long pos;
|
long pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct packet {
|
||||||
|
ssize_t size;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
struct desync_params {
|
struct desync_params {
|
||||||
int ttl;
|
int ttl;
|
||||||
char *ip_options;
|
char *ip_options;
|
||||||
ssize_t ip_options_len;
|
ssize_t ip_options_len;
|
||||||
char md5sig;
|
char md5sig;
|
||||||
|
struct packet fake_data;
|
||||||
|
|
||||||
int parts_n;
|
int parts_n;
|
||||||
struct part *parts;
|
struct part *parts;
|
||||||
|
|
||||||
int mod_http;
|
int mod_http;
|
||||||
int tlsrec_n;
|
int tlsrec_n;
|
||||||
struct part *tlsrec;
|
struct part *tlsrec;
|
||||||
|
|
||||||
|
int proto;
|
||||||
int detect;
|
int detect;
|
||||||
struct mphdr *hosts;
|
struct mphdr *hosts;
|
||||||
|
|
||||||
@ -63,7 +73,6 @@ struct desync_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct params {
|
struct params {
|
||||||
char de_known;
|
|
||||||
int dp_count;
|
int dp_count;
|
||||||
struct desync_params *dp;
|
struct desync_params *dp;
|
||||||
long sfdelay;
|
long sfdelay;
|
||||||
@ -77,6 +86,7 @@ struct params {
|
|||||||
long cache_ttl;
|
long cache_ttl;
|
||||||
char ipv6;
|
char ipv6;
|
||||||
char resolve;
|
char resolve;
|
||||||
|
char udp;
|
||||||
int max_open;
|
int max_open;
|
||||||
int debug;
|
int debug;
|
||||||
size_t bfsize;
|
size_t bfsize;
|
||||||
@ -86,10 +96,6 @@ struct params {
|
|||||||
|
|
||||||
extern struct params params;
|
extern struct params params;
|
||||||
|
|
||||||
struct packet {
|
|
||||||
ssize_t size;
|
|
||||||
char *data;
|
|
||||||
};
|
|
||||||
extern struct packet fake_tls;
|
extern struct packet fake_tls;
|
||||||
extern struct packet fake_http;
|
extern struct packet fake_http;
|
||||||
extern struct packet oob_data;
|
extern struct packet oob_data;
|
||||||
|
560
proxy.c
560
proxy.c
@ -1,17 +1,16 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#define EID_STR
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include <proxy.h>
|
#include <proxy.h>
|
||||||
#include <params.h>
|
#include <params.h>
|
||||||
#include <conev.h>
|
#include <conev.h>
|
||||||
#include <desync.h>
|
#include <extend.h>
|
||||||
#include <packets.h>
|
|
||||||
#include <error.h>
|
#include <error.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -19,9 +18,6 @@
|
|||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
#define close(fd) closesocket(fd)
|
#define close(fd) closesocket(fd)
|
||||||
#ifndef TCP_MAXRT
|
|
||||||
#define TCP_MAXRT 5
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -65,6 +61,25 @@ void map_fix(struct sockaddr_ina *addr, char f6)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline char addr_equ(
|
||||||
|
struct sockaddr_ina *a, struct sockaddr_ina *b)
|
||||||
|
{
|
||||||
|
if (a->in.sin_port != b->in.sin_port) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (a->sa.sa_family == AF_INET) {
|
||||||
|
return
|
||||||
|
*((uint32_t *)(&a->in.sin_addr)) ==
|
||||||
|
*((uint32_t *)(&b->in.sin_addr));
|
||||||
|
}
|
||||||
|
return
|
||||||
|
*((uint64_t *)(&a->in6.sin6_addr)) ==
|
||||||
|
*((uint64_t *)(&b->in6.sin6_addr)) &&
|
||||||
|
*((uint64_t *)(&a->in6.sin6_addr) + 1) ==
|
||||||
|
*((uint64_t *)(&b->in6.sin6_addr) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int nb_socket(int domain, int type)
|
static inline int nb_socket(int domain, int type)
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -96,33 +111,12 @@ static inline int nb_socket(int domain, int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int set_timeout(int fd, unsigned int s)
|
|
||||||
{
|
|
||||||
#ifdef __linux__
|
|
||||||
if (setsockopt(fd, IPPROTO_TCP,
|
|
||||||
TCP_USER_TIMEOUT, (char *)&s, sizeof(s))) {
|
|
||||||
uniperror("setsockopt TCP_USER_TIMEOUT");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (setsockopt(fd, IPPROTO_TCP,
|
|
||||||
TCP_MAXRT, (char *)&s, sizeof(s))) {
|
|
||||||
uniperror("setsockopt TCP_MAXRT");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int resolve(char *host, int len,
|
int resolve(char *host, int len,
|
||||||
struct sockaddr_ina *addr)
|
struct sockaddr_ina *addr, int type)
|
||||||
{
|
{
|
||||||
struct addrinfo hints = {0}, *res = 0;
|
struct addrinfo hints = {0}, *res = 0;
|
||||||
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = type;
|
||||||
hints.ai_flags = AI_ADDRCONFIG;
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
hints.ai_family = params.ipv6 ? AF_UNSPEC : AF_INET;
|
hints.ai_family = params.ipv6 ? AF_UNSPEC : AF_INET;
|
||||||
|
|
||||||
@ -227,7 +221,7 @@ int s4_get_addr(char *buff, size_t n,
|
|||||||
if (len < 3 || len > 255) {
|
if (len < 3 || len > 255) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (resolve(id_end + 1, len, dst)) {
|
if (resolve(id_end + 1, len, dst, SOCK_STREAM)) {
|
||||||
LOG(LOG_E, "not resolved: %.*s\n", len, id_end + 1);
|
LOG(LOG_E, "not resolved: %.*s\n", len, id_end + 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -241,25 +235,21 @@ int s4_get_addr(char *buff, size_t n,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int s5_get_addr(char *buffer, ssize_t n,
|
int s5_get_addr(char *buffer, size_t n,
|
||||||
struct sockaddr_ina *addr)
|
struct sockaddr_ina *addr, int type)
|
||||||
{
|
{
|
||||||
if (n < S_SIZE_MIN) {
|
if (n < S_SIZE_MIN) {
|
||||||
LOG(LOG_E, "ss: request to small\n");
|
LOG(LOG_E, "ss: request to small\n");
|
||||||
return -1;
|
return -S_ER_GEN;
|
||||||
}
|
}
|
||||||
struct s5_req *r = (struct s5_req *)buffer;
|
struct s5_req *r = (struct s5_req *)buffer;
|
||||||
|
|
||||||
int o = (r->atp == S_ATP_I4 ? S_SIZE_I4 :
|
size_t o = (r->atp == S_ATP_I4 ? S_SIZE_I4 :
|
||||||
(r->atp == S_ATP_ID ? r->id.len + S_SIZE_ID :
|
(r->atp == S_ATP_ID ? r->id.len + S_SIZE_ID :
|
||||||
(r->atp == S_ATP_I6 ? S_SIZE_I6 : 0)));
|
(r->atp == S_ATP_I6 ? S_SIZE_I6 : 0)));
|
||||||
if (n < o) {
|
if (n < o) {
|
||||||
LOG(LOG_E, "ss: bad request\n");
|
LOG(LOG_E, "ss: bad request\n");
|
||||||
return S_ER_GEN;
|
return -S_ER_GEN;
|
||||||
}
|
|
||||||
if (r->cmd != S_CMD_CONN) {
|
|
||||||
LOG(LOG_E, "ss: unsupported cmd: 0x%x\n", r->cmd);
|
|
||||||
return S_ER_CMD;
|
|
||||||
}
|
}
|
||||||
switch (r->atp) {
|
switch (r->atp) {
|
||||||
case S_ATP_I4:
|
case S_ATP_I4:
|
||||||
@ -269,24 +259,55 @@ int s5_get_addr(char *buffer, ssize_t n,
|
|||||||
|
|
||||||
case S_ATP_ID:
|
case S_ATP_ID:
|
||||||
if (!params.resolve) {
|
if (!params.resolve) {
|
||||||
return S_ER_ATP;
|
return -S_ER_ATP;
|
||||||
}
|
}
|
||||||
if (r->id.len < 3 ||
|
if (r->id.len < 3 ||
|
||||||
resolve(r->id.domain, r->id.len, addr)) {
|
resolve(r->id.domain, r->id.len, addr, type)) {
|
||||||
LOG(LOG_E, "not resolved: %.*s\n", r->id.len, r->id.domain);
|
LOG(LOG_E, "not resolved: %.*s\n", r->id.len, r->id.domain);
|
||||||
return S_ER_HOST;
|
return -S_ER_HOST;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_ATP_I6:
|
case S_ATP_I6:
|
||||||
if (!params.ipv6)
|
if (!params.ipv6)
|
||||||
return S_ER_ATP;
|
return -S_ER_ATP;
|
||||||
else {
|
else {
|
||||||
addr->in6.sin6_family = AF_INET6;
|
addr->in6.sin6_family = AF_INET6;
|
||||||
addr->in6.sin6_addr = r->i6;
|
addr->in6.sin6_addr = r->i6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addr->in.sin_port = *(uint16_t *)&buffer[o - 2];
|
addr->in.sin_port = *(uint16_t *)&buffer[o - 2];
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int s5_set_addr(char *buffer, size_t n,
|
||||||
|
struct sockaddr_ina *addr, char end)
|
||||||
|
{
|
||||||
|
struct s5_req *r = (struct s5_req *)buffer;
|
||||||
|
if (n < S_SIZE_I4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (addr->sa.sa_family == AF_INET) {
|
||||||
|
if (end) {
|
||||||
|
r = (struct s5_req *)(buffer - S_SIZE_I4);
|
||||||
|
}
|
||||||
|
r->atp = S_ATP_I4;
|
||||||
|
r->i4 = addr->in.sin_addr;
|
||||||
|
r->p4 = addr->in.sin_port;
|
||||||
|
return S_SIZE_I4;
|
||||||
|
} else {
|
||||||
|
if (n < S_SIZE_I6) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (end) {
|
||||||
|
r = (struct s5_req *)(buffer - S_SIZE_I6);
|
||||||
|
}
|
||||||
|
r->atp = S_ATP_I6;
|
||||||
|
r->i6 = addr->in6.sin6_addr;
|
||||||
|
r->p6 = addr->in6.sin6_port;
|
||||||
|
return S_SIZE_I6;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,6 +390,62 @@ int create_conn(struct poolhd *pool,
|
|||||||
pair->pair = val;
|
pair->pair = val;
|
||||||
pair->in6 = dst->in6;
|
pair->in6 = dst->in6;
|
||||||
pair->flag = FLAG_CONN;
|
pair->flag = FLAG_CONN;
|
||||||
|
val->type = EV_IGNORE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int udp_associate(struct poolhd *pool,
|
||||||
|
struct eval *val, struct sockaddr_ina *dst)
|
||||||
|
{
|
||||||
|
struct sockaddr_ina addr = {};
|
||||||
|
|
||||||
|
int ufd = nb_socket(params.baddr.sin6_family, SOCK_DGRAM);
|
||||||
|
if (ufd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (params.baddr.sin6_family == AF_INET6) {
|
||||||
|
int no = 0;
|
||||||
|
if (setsockopt(ufd, IPPROTO_IPV6,
|
||||||
|
IPV6_V6ONLY, (char *)&no, sizeof(no))) {
|
||||||
|
perror("setsockopt IPV6_V6ONLY");
|
||||||
|
close(ufd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bind(ufd, (struct sockaddr *)¶ms.baddr,
|
||||||
|
sizeof(params.baddr)) < 0) {
|
||||||
|
uniperror("bind");
|
||||||
|
close(ufd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
socklen_t sz = sizeof(addr);
|
||||||
|
if (getsockname(ufd, &addr.sa, &sz)) {
|
||||||
|
perror("getsockname");
|
||||||
|
close(ufd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct eval *pair = add_event(pool, EV_UDP_TUNNEL, ufd, POLLIN);
|
||||||
|
if (!pair) {
|
||||||
|
close(ufd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val->pair = pair;
|
||||||
|
pair->pair = val;
|
||||||
|
pair->in6.sin6_port = 0;
|
||||||
|
|
||||||
|
struct s5_req s5r = {
|
||||||
|
.ver = 0x05
|
||||||
|
};
|
||||||
|
int len = s5_set_addr((char *)&s5r, sizeof(s5r), &addr, 0);
|
||||||
|
if (len < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (send(val->fd, (char *)&s5r, len, 0) < 0) {
|
||||||
|
perror("send");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +499,7 @@ static inline int on_accept(struct poolhd *pool, struct eval *val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int on_tunnel(struct poolhd *pool, struct eval *val,
|
int on_tunnel(struct poolhd *pool, struct eval *val,
|
||||||
char *buffer, size_t bfsize, int out)
|
char *buffer, size_t bfsize, int out)
|
||||||
{
|
{
|
||||||
ssize_t n = 0;
|
ssize_t n = 0;
|
||||||
@ -494,60 +571,64 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int mode_add_get(struct sockaddr_ina *dst, int m)
|
int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
|
||||||
{
|
{
|
||||||
// m < 0: get, m > 0: set, m == 0: delete
|
char *data = buffer + S_SIZE_I6;
|
||||||
time_t t;
|
size_t data_len = bfsize - S_SIZE_I6;
|
||||||
struct elem *val;
|
do {
|
||||||
char *str = (char *)&dst->in;
|
struct sockaddr_ina addr = {0};
|
||||||
int len = sizeof(dst->sa.sa_family);
|
struct sockaddr_ina *src = (struct sockaddr_ina *)&val->in6;
|
||||||
|
socklen_t asz = sizeof(addr);
|
||||||
if (dst->sa.sa_family == AF_INET) {
|
|
||||||
len = sizeof(dst->in);
|
ssize_t n = recvfrom(val->fd, data, data_len, 0, &addr.sa, &asz);
|
||||||
}
|
if (n < 1) {
|
||||||
else {
|
if (n && errno == EAGAIN)
|
||||||
len = sizeof(dst->in6) - sizeof(dst->in6.sin6_scope_id);
|
break;
|
||||||
}
|
perror("recv udp");
|
||||||
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, str, len);
|
|
||||||
if (!val) {
|
|
||||||
uniperror("mem_add");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->m = m;
|
if (!src->in.sin_port) {
|
||||||
val->time = t;
|
src->in6 = addr.in6;
|
||||||
return 0;
|
}
|
||||||
}
|
ssize_t ns = 0;
|
||||||
val = mem_get(params.mempool, str, len);
|
|
||||||
if (!val) {
|
if (addr_equ(src, &addr)) {
|
||||||
return -1;
|
if (*(data + 2) != 0) { // frag
|
||||||
}
|
continue;
|
||||||
time(&t);
|
}
|
||||||
if (t > val->time + params.cache_ttl) {
|
int offs = s5_get_addr(data, n, &addr, SOCK_DGRAM);
|
||||||
LOG(LOG_S, "time=%ld, now=%ld, ignore\n", val->time, t);
|
if (offs < 0) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
return val->m;
|
val->pair->in6 = addr.in6;
|
||||||
}
|
|
||||||
|
if (src->sa.sa_family == AF_INET6) {
|
||||||
|
map_fix(&addr, 6);
|
||||||
int ext_connect(struct poolhd *pool, struct eval *val,
|
}
|
||||||
struct sockaddr_ina *dst, int next, int m)
|
if (src->sa.sa_family != addr.sa.sa_family) {
|
||||||
{
|
return -1;
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
}
|
||||||
if (dp->to_ip == 2) {
|
ns = udp_hook(val,
|
||||||
struct sockaddr_ina addr = { .in6 = dp->addr };
|
data + offs, n - offs, &addr);
|
||||||
addr.in.sin_port = dst->in.sin_port;
|
}
|
||||||
return create_conn(pool, val, &addr, next);
|
else {
|
||||||
}
|
//map_fix(&addr, 0);
|
||||||
return create_conn(pool, val, dst, next);
|
memset(buffer, 0, S_SIZE_I6);
|
||||||
|
|
||||||
|
int offs = s5_set_addr(data, S_SIZE_I6,
|
||||||
|
(struct sockaddr_ina *)&val->pair->in6, 1);
|
||||||
|
if (offs < 0 || offs > S_SIZE_I6) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ns = sendto(val->fd, data - offs, offs + n, 0,
|
||||||
|
(struct sockaddr *)&val->in6, sizeof(val->in6));
|
||||||
|
}
|
||||||
|
if (ns < 0) {
|
||||||
|
perror("sendto");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} while(1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -571,268 +652,58 @@ static inline int on_request(struct poolhd *pool, struct eval *val,
|
|||||||
val->flag = FLAG_S5;
|
val->flag = FLAG_S5;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
error = s5_get_addr(buffer, n, &dst);
|
if (n < S_SIZE_MIN) {
|
||||||
|
LOG(LOG_E, "ss: request to small (%ld)\n", n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct s5_req *r = (struct s5_req *)buffer;
|
||||||
|
int s5e = 0;
|
||||||
|
switch (r->cmd) {
|
||||||
|
case S_CMD_CONN:
|
||||||
|
s5e = s5_get_addr(buffer, n, &dst, SOCK_STREAM);
|
||||||
|
if (s5e >= 0) {
|
||||||
|
error = connect_hook(pool, val, &dst, EV_CONNECT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_CMD_AUDP:
|
||||||
|
if (params.udp) {
|
||||||
|
s5e = s5_get_addr(buffer, n, &dst, SOCK_DGRAM);
|
||||||
|
if (s5e >= 0) {
|
||||||
|
error = udp_associate(pool, val, &dst);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG(LOG_E, "ss: unsupported cmd: 0x%x\n", r->cmd);
|
||||||
|
s5e = -S_ER_CMD;
|
||||||
|
}
|
||||||
|
if (s5e < 0) {
|
||||||
|
if (resp_s5_error(val->fd, -s5e) < 0)
|
||||||
|
perror("send");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (*buffer == S_VER4) {
|
else if (*buffer == S_VER4) {
|
||||||
val->flag = FLAG_S4;
|
val->flag = FLAG_S4;
|
||||||
|
|
||||||
error = s4_get_addr(buffer, n, &dst);
|
error = s4_get_addr(buffer, n, &dst);
|
||||||
|
if (error) {
|
||||||
|
if (resp_error(val->fd, error, FLAG_S4) < 0)
|
||||||
|
perror("send");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
error = connect_hook(pool, val, &dst, EV_CONNECT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LOG_E, "ss: invalid version: 0x%x (%lu)\n", *buffer, n);
|
LOG(LOG_E, "ss: invalid version: 0x%x (%lu)\n", *buffer, n);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (error) {
|
|
||||||
if ((val->flag == FLAG_S4
|
|
||||||
&& resp_error(val->fd, error, FLAG_S4) < 0)
|
|
||||||
|| (resp_s5_error(val->fd, error) < 0)) {
|
|
||||||
uniperror("send");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
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) {
|
if (error) {
|
||||||
int en = get_e();
|
int en = get_e();
|
||||||
if (resp_error(val->fd, en ? en : error, val->flag) < 0)
|
if (resp_error(val->fd, en ? en : error, val->flag) < 0)
|
||||||
uniperror("send");
|
uniperror("send");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
val->type = EV_IGNORE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int reconnect(struct poolhd *pool, struct eval *val, int m)
|
|
||||||
{
|
|
||||||
struct eval *client = val->pair;
|
|
||||||
|
|
||||||
if (ext_connect(pool, client,
|
|
||||||
(struct sockaddr_ina *)&val->in6, EV_DESYNC, m)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->pair = 0;
|
|
||||||
del_event(pool, val);
|
|
||||||
|
|
||||||
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 = ¶ms.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(
|
|
||||||
(struct sockaddr_ina *)&val->in6, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return reconnect(pool, val, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int on_response(struct poolhd *pool, struct eval *val,
|
|
||||||
char *resp, ssize_t sn)
|
|
||||||
{
|
|
||||||
int m = val->pair->attempt + 1;
|
|
||||||
|
|
||||||
char *req = val->pair->buff.data;
|
|
||||||
ssize_t qn = val->pair->buff.size;
|
|
||||||
|
|
||||||
for (; m < params.dp_count; m++) {
|
|
||||||
struct desync_params *dp = ¶ms.dp[m];
|
|
||||||
|
|
||||||
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) {
|
|
||||||
return reconnect(pool, val, m);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int on_tunnel_check(struct poolhd *pool, struct eval *val,
|
|
||||||
char *buffer, size_t bfsize, int out)
|
|
||||||
{
|
|
||||||
if (out) {
|
|
||||||
return on_tunnel(pool, val, buffer, bfsize, out);
|
|
||||||
}
|
|
||||||
ssize_t n = recv(val->fd, buffer, bfsize, 0);
|
|
||||||
if (n < 1) {
|
|
||||||
uniperror("recv");
|
|
||||||
switch (get_e()) {
|
|
||||||
case ECONNRESET:
|
|
||||||
case ETIMEDOUT:
|
|
||||||
break;
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
return on_torst(pool, val);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
if (on_response(pool, val, buffer, n) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
struct eval *pair = val->pair;
|
|
||||||
|
|
||||||
ssize_t sn = send(pair->fd, buffer, n, 0);
|
|
||||||
if (n != sn) {
|
|
||||||
uniperror("send");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->type = EV_TUNNEL;
|
|
||||||
pair->type = EV_TUNNEL;
|
|
||||||
|
|
||||||
free(pair->buff.data);
|
|
||||||
pair->buff.data = 0;
|
|
||||||
pair->buff.size = 0;
|
|
||||||
|
|
||||||
if (params.timeout &&
|
|
||||||
set_timeout(val->fd, 0)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int m = pair->attempt;
|
|
||||||
|
|
||||||
if (!pair->cache) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (m == 0) {
|
|
||||||
LOG(LOG_S, "delete ip: m=%d\n", m);
|
|
||||||
} else {
|
|
||||||
LOG(LOG_S, "save ip: m=%d\n", m);
|
|
||||||
}
|
|
||||||
return mode_add_get(
|
|
||||||
(struct sockaddr_ina *)&val->in6, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int on_desync(struct poolhd *pool, struct eval *val,
|
|
||||||
char *buffer, size_t bfsize)
|
|
||||||
{
|
|
||||||
if (val->flag == FLAG_CONN) {
|
|
||||||
if (mod_etype(pool, val, POLLOUT, 0)) {
|
|
||||||
uniperror("mod_etype");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val = val->pair;
|
|
||||||
}
|
|
||||||
ssize_t n;
|
|
||||||
int m = val->attempt;
|
|
||||||
LOG((m ? LOG_S : LOG_L), "desync params index: %d\n", m);
|
|
||||||
|
|
||||||
if (!val->buff.data) {
|
|
||||||
n = recv(val->fd, buffer, bfsize, 0);
|
|
||||||
if (n <= 0) {
|
|
||||||
if (n) uniperror("recv data");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->buff.size = n;
|
|
||||||
val->recv_count += n;
|
|
||||||
|
|
||||||
if (!(val->buff.data = malloc(n))) {
|
|
||||||
uniperror("malloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(val->buff.data, buffer, n);
|
|
||||||
|
|
||||||
if (!m) for (; m < params.dp_count; m++) {
|
|
||||||
struct desync_params *dp = ¶ms.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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (sn < n) {
|
|
||||||
val->buff.offset = sn;
|
|
||||||
if (mod_etype(pool, val->pair, POLLOUT, 1)) {
|
|
||||||
uniperror("mod_etype");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val->pair->type = EV_DESYNC;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
val->type = EV_TUNNEL;
|
|
||||||
val->pair->type = EV_PRE_TUNNEL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,6 +800,11 @@ int event_loop(int srvfd)
|
|||||||
del_event(pool, val);
|
del_event(pool, val);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case EV_UDP_TUNNEL:
|
||||||
|
if (on_udp_tunnel(val, buffer, bfsize))
|
||||||
|
del_event(pool, val);
|
||||||
|
continue;
|
||||||
|
|
||||||
case EV_CONNECT:
|
case EV_CONNECT:
|
||||||
if (on_connect(pool, val, etype & POLLERR))
|
if (on_connect(pool, val, etype & POLLERR))
|
||||||
del_event(pool, val);
|
del_event(pool, val);
|
||||||
|
14
proxy.h
14
proxy.h
@ -6,6 +6,8 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <conev.h>
|
||||||
|
|
||||||
struct sockaddr_ina {
|
struct sockaddr_ina {
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
@ -94,6 +96,18 @@ enum s4_rep {
|
|||||||
#define S_SIZE_I6 22
|
#define S_SIZE_I6 22
|
||||||
#define S_SIZE_ID 7
|
#define S_SIZE_ID 7
|
||||||
|
|
||||||
|
void map_fix(struct sockaddr_ina *addr, char f6);
|
||||||
|
|
||||||
|
int resp_error(int fd, int e, int flag);
|
||||||
|
|
||||||
|
int create_conn(struct poolhd *pool,
|
||||||
|
struct eval *val, struct sockaddr_ina *dst, int next);
|
||||||
|
|
||||||
|
int on_tunnel(struct poolhd *pool, struct eval *val,
|
||||||
|
char *buffer, size_t bfsize, int out);
|
||||||
|
|
||||||
int listen_socket(struct sockaddr_ina *srv);
|
int listen_socket(struct sockaddr_ina *srv);
|
||||||
|
|
||||||
int event_loop(int srvfd);
|
int event_loop(int srvfd);
|
||||||
|
|
||||||
int run(struct sockaddr_ina *srv);
|
int run(struct sockaddr_ina *srv);
|
||||||
|
27
readme.txt
27
readme.txt
@ -31,6 +31,9 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
|
|||||||
Отбрасывать запросы, если в качестве адреса указан домен
|
Отбрасывать запросы, если в качестве адреса указан домен
|
||||||
Т.к. резолвинг выполняется синхронно, то он может замедлить или даже заморозить работу
|
Т.к. резолвинг выполняется синхронно, то он может замедлить или даже заморозить работу
|
||||||
|
|
||||||
|
-U, --no-udp
|
||||||
|
Не проксировать UDP
|
||||||
|
|
||||||
-K, --desync-known
|
-K, --desync-known
|
||||||
Отключить запутывание для нераспознанных протоколов
|
Отключить запутывание для нераспознанных протоколов
|
||||||
Распознаваемые протоколы: HTTP и TLS с SNI
|
Распознаваемые протоколы: HTTP и TLS с SNI
|
||||||
@ -54,12 +57,12 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
|
|||||||
cl_err : HTTP ответ, код которого равен 40x, но не 429
|
cl_err : HTTP ответ, код которого равен 40x, но не 429
|
||||||
sid_inv : session_id в TLS ServerHello и ClientHello не совпадают
|
sid_inv : session_id в TLS ServerHello и ClientHello не совпадают
|
||||||
alert : TLS Error Alert в ответе
|
alert : TLS Error Alert в ответе
|
||||||
nop : Предыдущая группа пропущена, например из-за ограничения по hosts
|
none : Предыдущая группа пропущена, например из-за ограничения по доменам или протоколам
|
||||||
По умолчанию обрабатывается только torst
|
По умолчанию обрабатывается только torst
|
||||||
Можно указывать несколько групп опций, раделяя их данным параметром
|
Можно указывать несколько групп опций, раделяя их данным параметром
|
||||||
Если соединение успешно прошло, то параметры для данного IP будут закешированны
|
Если соединение успешно прошло, то параметры для данного IP будут закешированны
|
||||||
Параметры, которые можно вынести в отдельную группу:
|
Параметры, которые можно вынести в отдельную группу:
|
||||||
hosts, dst, split, disorder, oob, fake, ttl, ip-opt, md5sig, mod-http, tlsrec
|
proto, hosts, dst, split, disorder, oob, fake, ttl, ip-opt, md5sig, fake-data, mod-http, tlsrec
|
||||||
Пример:
|
Пример:
|
||||||
--auto=redirect --split=1+h --auto=torst --fake -1 --auto=sid_inv,alert --tlsrec 1+s
|
--auto=redirect --split=1+h --auto=torst --fake -1 --auto=sid_inv,alert --tlsrec 1+s
|
||||||
|
|
||||||
@ -71,6 +74,9 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
|
|||||||
В Linux переводится в миллисекунды, поэтому можно указать дробное число
|
В Linux переводится в миллисекунды, поэтому можно указать дробное число
|
||||||
Истечение таймаута будет обработано --auto
|
Истечение таймаута будет обработано --auto
|
||||||
|
|
||||||
|
-K, --proto[=t,h,d,q]
|
||||||
|
Белый список протоколов: tls,http,dns,quic
|
||||||
|
|
||||||
-H, --hosts <file|:string>
|
-H, --hosts <file|:string>
|
||||||
Ограничить область действия параметров списком доменов
|
Ограничить область действия параметров списком доменов
|
||||||
Домены должны быть разделены новой строкой или пробелом
|
Домены должны быть разделены новой строкой или пробелом
|
||||||
@ -113,8 +119,7 @@ $ ./ciadpi --disorder 3 -A --tlsrec 1+s
|
|||||||
Большинство серверов (в основном на Linux) отбрасывают пакеты с данной опцией
|
Большинство серверов (в основном на Linux) отбрасывают пакеты с данной опцией
|
||||||
Поддерживается только в Linux, может быть выключен в некоторых сборках ядра (< 3.9, Android)
|
Поддерживается только в Linux, может быть выключен в некоторых сборках ядра (< 3.9, Android)
|
||||||
|
|
||||||
-l, --fake-tls <file|:str>
|
-l, --fake-data <file|:str>
|
||||||
-j, --fake-http <file|:str>
|
|
||||||
Указать свои поддельные пакеты, вместо дефолтных
|
Указать свои поддельные пакеты, вместо дефолтных
|
||||||
|
|
||||||
-e, --oob-data <file|:str>
|
-e, --oob-data <file|:str>
|
||||||
@ -228,25 +233,31 @@ TCP может отсылать данные вне основного пото
|
|||||||
--auto, --hosts
|
--auto, --hosts
|
||||||
Параметр auto делит опции на группы.
|
Параметр auto делит опции на группы.
|
||||||
Для каждого запроса они обходятся слева на право.
|
Для каждого запроса они обходятся слева на право.
|
||||||
Сначала проверяется триггер указанный в auto, затем hosts.
|
Сначала проверяется триггер, указанный в auto, затем proto и hosts.
|
||||||
|
|
||||||
Примеры:
|
Примеры:
|
||||||
--fake -1 --ttl 10 --auto=alert,sid_inv --fake -1 --ttl 5
|
--fake -1 --ttl 10 --auto=alert,sid_inv --fake -1 --ttl 5
|
||||||
По умолчанию использовать fake с ttl=10, в случае ошибки использовать fake с ttl=5
|
По умолчанию использовать fake с ttl=10, в случае ошибки использовать fake с ttl=5
|
||||||
|
|
||||||
--hosts list.txt --disorder 3 --auto=nop
|
--hosts list.txt --disorder 3 --auto=none
|
||||||
Применять запутывание только для доменов из list.txt
|
Применять запутывание только для доменов из list.txt
|
||||||
|
|
||||||
--hosts list.txt --auto=nop --disorder 3
|
--hosts list.txt --auto=none --disorder 3
|
||||||
Не применять запутывание для доменов из list.txt
|
Не применять запутывание для доменов из list.txt
|
||||||
|
|
||||||
--late-conn --hosts ':one.one.one.one' --dst 1.1.1.1 --disorder 3 --auto=nop --auto=torst --timeout 3 --tlsrec 1+s
|
--late-conn --hosts ':one.one.one.one' --dst 1.1.1.1 --disorder 3 --auto=none --auto=torst --timeout 3 --tlsrec 1+s
|
||||||
Для указанного домена применять disorder, подключаясь только на указанный IP и игнорируя адрес из запроса.
|
Для указанного домена применять disorder, подключаясь только на указанный IP и игнорируя адрес из запроса.
|
||||||
Для остальных ничего не делать, однако если обнаружится блокировка, то попробовать применить tlsrec.
|
Для остальных ничего не делать, однако если обнаружится блокировка, то попробовать применить tlsrec.
|
||||||
|
|
||||||
--auto=torst --hosts list.txt --disorder 3
|
--auto=torst --hosts list.txt --disorder 3
|
||||||
По умолчанию ничего не делать, использовать disorder при условии, что произошла блокировка и домен входит в list.txt.
|
По умолчанию ничего не делать, использовать disorder при условии, что произошла блокировка и домен входит в list.txt.
|
||||||
|
|
||||||
|
--proto=http,tls --disorder 3 --auto=none
|
||||||
|
Запутывать только HTTP и TLS
|
||||||
|
|
||||||
|
--proto=http --fake -1 --fake-data=':GET /...' --auto=none --fake -1
|
||||||
|
Переопределить фейковый пакет для HTTP
|
||||||
|
|
||||||
-------
|
-------
|
||||||
Сборка:
|
Сборка:
|
||||||
Для сборки понадобится:
|
Для сборки понадобится:
|
||||||
|
Loading…
Reference in New Issue
Block a user