byedpi/proxy.c

1032 lines
26 KiB
C
Raw Normal View History

2024-04-23 08:47:27 +03:00
#define EID_STR
2023-06-03 22:52:10 +03:00
2024-08-07 14:25:26 +03:00
#include "proxy.h"
2023-06-03 22:52:10 +03:00
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
2023-06-03 22:52:10 +03:00
2024-05-02 19:36:29 +03:00
#include "params.h"
#include "conev.h"
#include "extend.h"
#include "error.h"
2024-02-18 23:20:52 +03:00
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define close(fd) closesocket(fd)
#else
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#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"
2024-09-17 22:51:39 +03:00
#ifndef IP6T_SO_ORIGINAL_DST
#define IP6T_SO_ORIGINAL_DST SO_ORIGINAL_DST
#endif
#endif
2024-02-18 23:20:52 +03:00
#endif
2023-06-03 22:52:10 +03:00
2023-06-03 22:52:10 +03:00
int NOT_EXIT = 1;
static void on_cancel(int sig) {
NOT_EXIT = 0;
}
2023-07-07 16:26:04 +03:00
2023-07-08 21:04:24 +03:00
void map_fix(struct sockaddr_ina *addr, char f6)
2023-07-07 16:26:04 +03:00
{
struct {
uint64_t o64;
uint16_t o16;
uint16_t t16;
uint32_t o32;
} *ipv6m = (void *)&addr->in6.sin6_addr;
if (addr->sa.sa_family == AF_INET && f6) {
addr->sa.sa_family = AF_INET6;
ipv6m->o32 = *(uint32_t *)(&addr->in.sin_addr);
ipv6m->o64 = 0;
ipv6m->o16 = 0;
ipv6m->t16 = 0xffff;
}
2023-08-20 16:30:03 +03:00
else if (!ipv6m->o64 && !ipv6m->o16 &&
2023-07-07 21:30:53 +03:00
ipv6m->t16 == 0xffff && !f6) {
2023-07-07 16:26:04 +03:00
addr->sa.sa_family = AF_INET;
const struct in_addr *sin_addr_ptr = (struct in_addr *) &ipv6m->o32;
addr->in.sin_addr = *sin_addr_ptr;
2023-07-07 16:26:04 +03:00
}
}
2024-04-23 08:47:27 +03:00
static inline char addr_equ(
2024-11-09 18:07:27 +03:00
const struct sockaddr_ina *a, const struct sockaddr_ina *b)
2024-04-23 08:47:27 +03:00
{
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)
{
2023-07-07 16:26:04 +03:00
#ifdef __linux__
int fd = socket(domain, type | SOCK_NONBLOCK, 0);
#else
int fd = socket(domain, type, 0);
#endif
if (fd < 0) {
2024-02-18 23:20:52 +03:00
uniperror("socket");
return -1;
}
#ifdef _WIN32
unsigned long mode = 1;
if (ioctlsocket(fd, FIONBIO, &mode) < 0) {
uniperror("ioctlsocket");
close(fd);
2023-07-07 16:26:04 +03:00
return -1;
}
2024-02-18 23:20:52 +03:00
#else
2023-07-07 16:26:04 +03:00
#ifndef __linux__
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
2024-02-24 20:44:54 +03:00
uniperror("fcntl");
2023-07-07 16:26:04 +03:00
close(fd);
return -1;
}
#endif
2024-02-18 23:20:52 +03:00
#endif
2023-07-07 16:26:04 +03:00
return fd;
}
2024-11-09 18:07:27 +03:00
static int resolve(char *host, int len,
2024-04-23 08:47:27 +03:00
struct sockaddr_ina *addr, int type)
2023-06-03 22:52:10 +03:00
{
struct addrinfo hints = {0}, *res = 0;
2024-04-23 08:47:27 +03:00
hints.ai_socktype = type;
2023-06-03 22:52:10 +03:00
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = params.ipv6 ? AF_UNSPEC : AF_INET;
2023-06-03 22:52:10 +03:00
char rchar = host[len];
host[len] = '\0';
2024-09-17 22:51:39 +03:00
LOG(LOG_S, "resolve: %s\n", host);
2023-06-03 22:52:10 +03:00
if (getaddrinfo(host, 0, &hints, &res) || !res) {
host[len] = rchar;
return -1;
}
if (res->ai_addr->sa_family == AF_INET6)
addr->in6 = *(struct sockaddr_in6 *)res->ai_addr;
else
addr->in = *(struct sockaddr_in *)res->ai_addr;
freeaddrinfo(res);
host[len] = rchar;
return 0;
}
2024-11-09 18:07:27 +03:00
static int auth_socks5(int fd, const char *buffer, ssize_t n)
2023-06-03 22:52:10 +03:00
{
if (n <= 2 || (uint8_t)buffer[1] != (n - 2)) {
return -1;
}
2023-11-23 22:27:39 +03:00
uint8_t c = S_AUTH_BAD;
for (long i = 2; i < n; i++)
2023-06-03 22:52:10 +03:00
if (buffer[i] == S_AUTH_NONE) {
2023-11-23 22:27:39 +03:00
c = S_AUTH_NONE;
2023-06-03 22:52:10 +03:00
break;
}
2024-11-09 18:07:27 +03:00
uint8_t a[2] = { S_VER5, c };
if (send(fd, a, sizeof(a), 0) < 0) {
2024-02-18 23:20:52 +03:00
uniperror("send");
2023-06-03 22:52:10 +03:00
return -1;
}
2023-11-23 22:27:39 +03:00
return c != S_AUTH_BAD ? 0 : -1;
2023-06-03 22:52:10 +03:00
}
2024-11-09 18:07:27 +03:00
static int resp_s5_error(int fd, int e)
2023-10-28 17:15:54 +03:00
{
struct s5_rep s5r = {
.ver = 0x05, .code = (uint8_t )e,
.atp = S_ATP_I4
};
return send(fd, (char *)&s5r, sizeof(s5r), 0);
}
2024-11-09 18:07:27 +03:00
static int resp_error(int fd, int e, int flag)
2023-06-03 22:52:10 +03:00
{
2023-08-20 16:30:03 +03:00
if (flag == FLAG_S4) {
2023-06-03 22:52:10 +03:00
struct s4_req s4r = {
.cmd = e ? S4_ER : S4_OK
};
return send(fd, (char *)&s4r, sizeof(s4r), 0);
2023-06-03 22:52:10 +03:00
}
2023-08-20 16:30:03 +03:00
else if (flag == FLAG_S5) {
2024-02-18 23:20:52 +03:00
switch (unie(e)) {
2023-10-28 17:15:54 +03:00
case 0: e = S_ER_OK;
2023-06-03 22:52:10 +03:00
break;
case ECONNREFUSED:
2023-10-28 17:15:54 +03:00
e = S_ER_CONN;
2023-06-03 22:52:10 +03:00
break;
case EHOSTUNREACH:
case ETIMEDOUT:
2023-10-28 17:15:54 +03:00
e = S_ER_HOST;
2023-06-03 22:52:10 +03:00
break;
case ENETUNREACH:
2023-10-28 17:15:54 +03:00
e = S_ER_NET;
2023-06-03 22:52:10 +03:00
break;
2023-10-28 17:15:54 +03:00
default: e = S_ER_GEN;
2023-06-03 22:52:10 +03:00
}
2023-10-28 17:15:54 +03:00
return resp_s5_error(fd, e);
2023-06-03 22:52:10 +03:00
}
#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
2023-06-03 22:52:10 +03:00
return 0;
}
2024-11-09 18:07:27 +03:00
static int s4_get_addr(const char *buff,
size_t n, struct sockaddr_ina *dst)
2023-06-03 22:52:10 +03:00
{
if (n < sizeof(struct s4_req) + 1) {
return -1;
}
2023-11-23 22:27:39 +03:00
struct s4_req *r = (struct s4_req *)buff;
2023-06-03 22:52:10 +03:00
if (r->cmd != S_CMD_CONN) {
2023-10-28 17:15:54 +03:00
return -1;
2023-06-03 22:52:10 +03:00
}
2023-10-28 17:15:54 +03:00
if (ntohl(r->i4.s_addr) <= 255) {
2023-11-23 22:27:39 +03:00
if (!params.resolve || buff[n - 1] != 0) {
2023-10-28 17:15:54 +03:00
return -1;
}
2023-11-23 22:27:39 +03:00
char *id_end = strchr(buff + sizeof(*r), 0);
2023-10-28 17:15:54 +03:00
if (!id_end) {
return -1;
}
2023-11-23 22:27:39 +03:00
int len = (buff + n - id_end) - 2;
2023-10-28 17:15:54 +03:00
if (len < 3 || len > 255) {
return -1;
}
2024-04-23 08:47:27 +03:00
if (resolve(id_end + 1, len, dst, SOCK_STREAM)) {
2024-02-24 20:44:54 +03:00
LOG(LOG_E, "not resolved: %.*s\n", len, id_end + 1);
2023-10-28 17:15:54 +03:00
return -1;
2023-06-03 22:52:10 +03:00
}
2023-10-28 17:15:54 +03:00
}
2023-06-03 22:52:10 +03:00
else {
dst->in.sin_family = AF_INET;
dst->in.sin_addr = r->i4;
}
dst->in.sin_port = r->port;
return 0;
}
2024-11-09 18:07:27 +03:00
static int s5_get_addr(const char *buffer,
size_t n, struct sockaddr_ina *addr, int type)
2023-06-03 22:52:10 +03:00
{
2024-03-13 22:18:16 +03:00
if (n < S_SIZE_MIN) {
LOG(LOG_E, "ss: request too small\n");
2024-04-23 08:47:27 +03:00
return -S_ER_GEN;
2024-03-13 22:18:16 +03:00
}
2023-06-03 22:52:10 +03:00
struct s5_req *r = (struct s5_req *)buffer;
2024-04-23 08:47:27 +03:00
size_t o = (r->atp == S_ATP_I4 ? S_SIZE_I4 :
2023-07-06 21:21:44 +03:00
(r->atp == S_ATP_ID ? r->id.len + S_SIZE_ID :
(r->atp == S_ATP_I6 ? S_SIZE_I6 : 0)));
if (n < o) {
2024-02-24 20:44:54 +03:00
LOG(LOG_E, "ss: bad request\n");
2024-04-23 08:47:27 +03:00
return -S_ER_GEN;
2023-10-28 17:15:54 +03:00
}
2023-07-06 21:21:44 +03:00
switch (r->atp) {
2023-06-03 22:52:10 +03:00
case S_ATP_I4:
addr->in.sin_family = AF_INET;
addr->in.sin_addr = r->i4;
break;
case S_ATP_ID:
if (!params.resolve) {
2024-04-23 08:47:27 +03:00
return -S_ER_ATP;
2023-06-03 22:52:10 +03:00
}
2023-10-10 21:24:46 +03:00
if (r->id.len < 3 ||
2024-04-23 08:47:27 +03:00
resolve(r->id.domain, r->id.len, addr, type)) {
2024-02-24 20:44:54 +03:00
LOG(LOG_E, "not resolved: %.*s\n", r->id.len, r->id.domain);
2024-04-23 08:47:27 +03:00
return -S_ER_HOST;
2023-06-03 22:52:10 +03:00
}
break;
case S_ATP_I6:
if (!params.ipv6)
2024-04-23 08:47:27 +03:00
return -S_ER_ATP;
2023-06-03 22:52:10 +03:00
else {
addr->in6.sin6_family = AF_INET6;
addr->in6.sin6_addr = r->i6;
}
}
2024-08-05 19:49:51 +03:00
memcpy(&addr->in.sin_port, &buffer[o - 2], sizeof(uint16_t));
2024-04-23 08:47:27 +03:00
return o;
}
2024-11-09 18:07:27 +03:00
static int s5_set_addr(char *buffer, size_t n,
const struct sockaddr_ina *addr, char end)
2024-04-23 08:47:27 +03:00
{
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;
}
2023-10-10 21:24:46 +03:00
return 0;
2023-07-06 21:21:44 +03:00
}
2024-10-22 18:30:08 +03:00
static int remote_sock(struct sockaddr_ina *dst, int type)
2023-06-03 22:52:10 +03:00
{
if (params.baddr.sin6_family == AF_INET6) {
2024-10-22 18:30:08 +03:00
map_fix(dst, 6);
2023-10-16 15:44:24 +03:00
} else {
2024-10-22 18:30:08 +03:00
map_fix(dst, 0);
2023-10-16 15:44:24 +03:00
}
2024-10-22 18:30:08 +03:00
if (dst->sa.sa_family != params.baddr.sin6_family) {
2024-02-24 20:44:54 +03:00
LOG(LOG_E, "different addresses family\n");
2023-10-16 15:44:24 +03:00
return -1;
}
2024-10-22 18:30:08 +03:00
int sfd = nb_socket(dst->sa.sa_family, type);
2023-06-03 22:52:10 +03:00
if (sfd < 0) {
2024-02-18 23:20:52 +03:00
uniperror("socket");
2023-06-03 22:52:10 +03:00
return -1;
}
2024-11-09 18:07:27 +03:00
if (socket_mod(sfd) < 0) {
2024-04-28 17:57:40 +03:00
close(sfd);
2024-04-28 02:50:46 +03:00
return -1;
}
2024-10-22 18:30:08 +03:00
if (dst->sa.sa_family == AF_INET6) {
int no = 0;
if (setsockopt(sfd, IPPROTO_IPV6,
IPV6_V6ONLY, (char *)&no, sizeof(no))) {
2024-02-18 23:20:52 +03:00
uniperror("setsockopt IPV6_V6ONLY");
close(sfd);
return -1;
}
}
if (bind(sfd, (struct sockaddr *)&params.baddr,
SA_SIZE(&params.baddr)) < 0) {
2024-02-18 23:20:52 +03:00
uniperror("bind");
close(sfd);
return -1;
}
2024-10-22 18:30:08 +03:00
return sfd;
}
int create_conn(struct poolhd *pool,
2024-11-09 18:07:27 +03:00
struct eval *val, const struct sockaddr_ina *dst, int next)
2024-10-22 18:30:08 +03:00
{
struct sockaddr_ina addr = *dst;
int sfd = remote_sock(&addr, SOCK_STREAM);
if (sfd < 0) {
return -1;
}
2023-06-03 22:52:10 +03:00
#ifdef __linux__
int syn_count = 1;
if (setsockopt(sfd, IPPROTO_TCP,
TCP_SYNCNT, (char *)&syn_count, sizeof(syn_count))) {
2024-02-18 23:20:52 +03:00
uniperror("setsockopt TCP_SYNCNT");
2023-06-03 22:52:10 +03:00
close(sfd);
return -1;
}
2024-03-20 02:23:56 +03:00
#ifdef TCP_FASTOPEN_CONNECT
int yes = 1;
if (params.tfo && setsockopt(sfd, IPPROTO_TCP,
TCP_FASTOPEN_CONNECT, (char *)&yes, sizeof(yes))) {
uniperror("setsockopt TCP_FASTOPEN_CONNECT");
close(sfd);
return -1;
}
#endif
2024-03-28 20:42:43 +03:00
#endif
int one = 1;
if (setsockopt(sfd, IPPROTO_TCP,
TCP_NODELAY, (char *)&one, sizeof(one))) {
2024-02-18 23:20:52 +03:00
uniperror("setsockopt TCP_NODELAY");
2023-06-03 22:52:10 +03:00
close(sfd);
return -1;
}
2024-11-09 16:20:13 +03:00
if (params.debug) {
INIT_ADDR_STR((*dst));
LOG(LOG_S, "new conn: fd=%d, pair=%d, addr=%s:%d\n",
sfd, val->fd, ADDR_STR, ntohs(dst->in.sin_port));
}
int status = connect(sfd, &addr.sa, SA_SIZE(&addr));
2024-03-21 01:01:36 +03:00
if (status == 0 && params.tfo) {
LOG(LOG_S, "TFO supported!\n");
}
2024-02-18 23:20:52 +03:00
if (status < 0 &&
get_e() != EINPROGRESS && get_e() != EAGAIN) {
uniperror("connect");
2023-06-03 22:52:10 +03:00
close(sfd);
return -1;
}
2024-03-11 18:38:39 +03:00
struct eval *pair = add_event(pool, next, sfd, POLLOUT);
2023-06-03 22:52:10 +03:00
if (!pair) {
close(sfd);
return -1;
}
if (mod_etype(pool, val, 0) < 0) {
uniperror("mod_etype");
return -1;
}
2023-06-03 22:52:10 +03:00
val->pair = pair;
pair->pair = val;
2024-08-22 17:53:17 +03:00
#ifdef __NetBSD__
pair->in6 = addr.in6;
2024-08-22 17:53:17 +03:00
#else
2024-03-28 23:28:09 +03:00
pair->in6 = dst->in6;
2024-08-22 17:53:17 +03:00
#endif
2023-06-03 22:52:10 +03:00
pair->flag = FLAG_CONN;
2024-10-20 18:50:08 +03:00
//val->type = EV_IGNORE;
2024-04-23 08:47:27 +03:00
return 0;
}
2024-11-09 18:07:27 +03:00
static int udp_associate(struct poolhd *pool,
struct eval *val, const struct sockaddr_ina *dst)
2024-04-23 08:47:27 +03:00
{
2024-07-23 14:50:17 +03:00
struct sockaddr_ina addr = *dst;
2024-04-23 08:47:27 +03:00
2024-10-22 18:30:08 +03:00
int ufd = remote_sock(&addr, SOCK_DGRAM);
2024-04-23 08:47:27 +03:00
if (ufd < 0) {
return -1;
}
struct eval *pair = add_event(pool, EV_UDP_TUNNEL, ufd, POLLIN);
if (!pair) {
2024-04-23 08:47:27 +03:00
close(ufd);
return -1;
}
2024-07-23 14:50:17 +03:00
if (dst->in6.sin6_port != 0) {
2024-08-16 19:10:09 +03:00
if (connect(ufd, &addr.sa, SA_SIZE(&addr)) < 0) {
uniperror("connect");
2024-08-14 15:20:35 +03:00
del_event(pool, pair);
return -1;
}
2024-07-29 22:14:57 +03:00
pair->in6 = addr.in6;
2024-07-23 14:50:17 +03:00
}
//
socklen_t sz = sizeof(addr);
if (getsockname(val->fd, &addr.sa, &sz)) {
uniperror("getsockname");
return -1;
}
addr.in.sin_port = 0;
int cfd = nb_socket(addr.sa.sa_family, SOCK_DGRAM);
if (cfd < 0) {
2024-05-04 22:57:38 +03:00
uniperror("socket");
del_event(pool, pair);
return -1;
}
if (bind(cfd, &addr.sa, SA_SIZE(&addr)) < 0) {
uniperror("bind");
del_event(pool, pair);
close(cfd);
return -1;
}
struct eval *client = add_event(pool, EV_UDP_TUNNEL, cfd, POLLIN);
if (!client) {
del_event(pool, pair);
close(cfd);
2024-04-23 08:47:27 +03:00
return -1;
}
2024-10-20 18:50:08 +03:00
if (params.debug) {
INIT_ADDR_STR((*dst));
2024-11-09 16:20:13 +03:00
LOG(LOG_S, "udp associate: fds=%d,%d,%d addr=%s:%d\n",
ufd, cfd, val->fd, ADDR_STR, ntohs(dst->in.sin_port));
2024-10-20 18:50:08 +03:00
}
val->type = EV_IGNORE;
val->pair = client;
client->pair = pair;
2024-04-23 08:47:27 +03:00
pair->pair = val;
client->flag = FLAG_CONN;
client->in6 = val->in6;
client->in6.sin6_port = 0;
2024-07-23 14:50:17 +03:00
sz = sizeof(addr);
if (getsockname(cfd, &addr.sa, &sz)) {
2024-05-04 22:57:38 +03:00
uniperror("getsockname");
return -1;
}
2024-04-23 08:47:27 +03:00
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) {
2024-05-04 22:57:38 +03:00
uniperror("send");
return -1;
}
if (mod_etype(pool, val, 0)) {
uniperror("mod_etype");
2024-04-23 08:47:27 +03:00
return -1;
}
2023-06-03 22:52:10 +03:00
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);
2024-09-17 22:51:39 +03:00
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
2023-06-03 22:52:10 +03:00
2024-11-09 18:07:27 +03:00
static int on_accept(struct poolhd *pool, const struct eval *val)
2023-06-03 22:52:10 +03:00
{
struct sockaddr_ina client;
struct eval *rval;
while (1) {
socklen_t len = sizeof(client);
2023-07-30 14:23:11 +03:00
#ifdef __linux__
int c = accept4(val->fd, &client.sa, &len, SOCK_NONBLOCK);
#else
2023-06-03 22:52:10 +03:00
int c = accept(val->fd, &client.sa, &len);
2023-07-30 14:23:11 +03:00
#endif
2023-06-03 22:52:10 +03:00
if (c < 0) {
2024-02-18 23:20:52 +03:00
if (get_e() == EAGAIN ||
get_e() == EINPROGRESS)
2023-06-03 22:52:10 +03:00
break;
2024-02-18 23:20:52 +03:00
uniperror("accept");
2023-06-03 22:52:10 +03:00
return -1;
}
2024-07-19 01:53:25 +03:00
LOG(LOG_S, "accept: fd=%d\n", c);
2023-07-30 14:23:11 +03:00
#ifndef __linux__
2024-02-18 23:20:52 +03:00
#ifdef _WIN32
unsigned long mode = 1;
if (ioctlsocket(c, FIONBIO, &mode) < 0) {
uniperror("ioctlsocket");
#else
2023-06-03 22:52:10 +03:00
if (fcntl(c, F_SETFL, O_NONBLOCK) < 0) {
2024-02-24 20:44:54 +03:00
uniperror("fcntl");
2024-02-18 23:20:52 +03:00
#endif
2023-06-03 22:52:10 +03:00
close(c);
continue;
}
2023-07-30 14:23:11 +03:00
#endif
int one = 1;
2023-10-16 15:44:24 +03:00
if (setsockopt(c, IPPROTO_TCP, TCP_NODELAY,
(char *)&one, sizeof(one))) {
2024-02-18 23:20:52 +03:00
uniperror("setsockopt TCP_NODELAY");
2023-06-03 22:52:10 +03:00
close(c);
continue;
}
if (!(rval = add_event(pool, EV_REQUEST, c, POLLIN))) {
2023-06-03 22:52:10 +03:00
close(c);
continue;
}
2023-07-07 16:26:04 +03:00
rval->in6 = client.in6;
#ifdef __linux__
if (params.transparent && transp_conn(pool, rval) < 0) {
del_event(pool, rval);
continue;
}
#endif
2023-06-03 22:52:10 +03:00
}
return 0;
}
2024-11-09 18:07:27 +03:00
static int on_tunnel(struct poolhd *pool, struct eval *val,
2024-05-17 14:06:29 +03:00
char *buffer, size_t bfsize, int etype)
2023-06-03 22:52:10 +03:00
{
ssize_t n = 0;
struct eval *pair = val->pair;
2024-05-17 14:06:29 +03:00
if (etype & POLLOUT) {
LOG(LOG_S, "pollout (fd=%d)\n", val->fd);
val = pair;
pair = val->pair;
}
if (val->buff.data) {
if (etype & POLLHUP) {
return -1;
}
2024-03-08 03:37:02 +03:00
n = val->buff.size - val->buff.offset;
2024-05-17 14:06:29 +03:00
2024-10-20 18:50:08 +03:00
ssize_t sn = tcp_send_hook(pair,
val->buff.data + val->buff.offset, n, n);
if (sn < 0) {
uniperror("send");
return -1;
}
if (sn < n) {
val->buff.offset += sn;
2023-10-28 15:31:54 +03:00
return 0;
}
2024-03-08 03:37:02 +03:00
free(val->buff.data);
val->buff.data = 0;
val->buff.size = 0;
val->buff.offset = 0;
2023-10-28 15:31:54 +03:00
if (mod_etype(pool, val, POLLIN) ||
mod_etype(pool, pair, POLLIN)) {
uniperror("mod_etype");
2024-01-23 03:08:35 +03:00
return -1;
}
2023-10-28 15:31:54 +03:00
}
do {
2024-10-20 18:50:08 +03:00
n = tcp_recv_hook(pool, val, buffer, bfsize);
//if (n < 0 && get_e() == EAGAIN) {
if (n == 0) {
2024-10-20 18:50:08 +03:00
break;
}
if (n < 0) {
2024-03-17 00:19:14 +03:00
return -1;
2023-10-28 15:31:54 +03:00
}
2024-10-20 18:50:08 +03:00
ssize_t sn = tcp_send_hook(pair, buffer, bfsize, n);
if (sn < 0) {
uniperror("send");
return -1;
}
2024-10-20 18:50:08 +03:00
if (sn < n) {
2024-11-09 16:20:13 +03:00
LOG(LOG_S, "send: %zd != %zd (fd=%d)\n", sn, n, pair->fd);
2024-05-17 14:06:29 +03:00
assert(!(val->buff.size || val->buff.offset));
2023-07-03 20:59:39 +03:00
2024-03-08 03:37:02 +03:00
val->buff.size = n - sn;
2024-05-17 14:06:29 +03:00
if (!(val->buff.data = malloc(n - sn))) {
2024-03-02 14:14:02 +03:00
uniperror("malloc");
2023-07-03 21:47:46 +03:00
return -1;
}
2024-05-17 14:06:29 +03:00
memcpy(val->buff.data, buffer + sn, n - sn);
2023-10-28 15:31:54 +03:00
if (mod_etype(pool, val, 0) ||
mod_etype(pool, pair, POLLOUT)) {
uniperror("mod_etype");
2024-01-23 03:08:35 +03:00
return -1;
}
2023-07-03 20:59:39 +03:00
break;
2023-06-03 22:52:10 +03:00
}
} while (n == bfsize);
return 0;
}
2024-11-09 18:07:27 +03:00
static int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
2024-03-08 03:37:02 +03:00
{
char *data = buffer;
size_t data_len = bfsize;
if (val->flag != FLAG_CONN) {
data += S_SIZE_I6;
data_len -= S_SIZE_I6;
}
struct sockaddr_ina addr = {0};
2024-10-20 18:50:08 +03:00
struct eval *pair = val->flag == FLAG_CONN ?
val->pair : val->pair->pair;
2024-04-23 08:47:27 +03:00
do {
socklen_t asz = sizeof(addr);
ssize_t n = recvfrom(val->fd, data, data_len, 0, &addr.sa, &asz);
2024-04-23 08:47:27 +03:00
if (n < 1) {
2024-07-23 14:50:17 +03:00
if (n && get_e() == EAGAIN)
2024-04-23 08:47:27 +03:00
break;
2024-05-04 22:57:38 +03:00
uniperror("recv udp");
2024-03-08 03:37:02 +03:00
return -1;
}
2024-07-23 14:50:17 +03:00
val->recv_count += n;
2024-10-20 18:50:08 +03:00
if (val->round_sent == 0) {
val->round_count++;
val->round_sent += n;
pair->round_sent = 0;
}
ssize_t ns;
2024-04-23 08:47:27 +03:00
if (val->flag == FLAG_CONN) {
if (!val->in6.sin6_port) {
2024-07-23 14:50:17 +03:00
if (!addr_equ(&addr, (struct sockaddr_ina *)&val->in6)) {
return 0;
}
if (connect(val->fd, &addr.sa, SA_SIZE(&addr)) < 0) {
uniperror("connect");
return -1;
}
val->in6 = addr.in6;
}
2024-04-23 08:47:27 +03:00
if (*(data + 2) != 0) { // frag
continue;
}
int offs = s5_get_addr(data, n, &addr, SOCK_DGRAM);
if (offs < 0) {
LOG(LOG_E, "udp parse error\n");
2024-04-23 08:47:27 +03:00
return -1;
}
2024-10-20 18:50:08 +03:00
if (!pair->in6.sin6_port) {
2024-07-23 14:50:17 +03:00
if (params.baddr.sin6_family == AF_INET6) {
map_fix(&addr, 6);
}
if (params.baddr.sin6_family != addr.sa.sa_family) {
return -1;
}
2024-10-20 18:50:08 +03:00
if (connect(pair->fd, &addr.sa, SA_SIZE(&addr)) < 0) {
2024-08-16 19:10:09 +03:00
uniperror("connect");
2024-08-14 15:20:35 +03:00
return -1;
}
2024-10-20 18:50:08 +03:00
pair->in6 = addr.in6;
2024-04-23 08:47:27 +03:00
}
2024-10-20 18:50:08 +03:00
ns = udp_hook(pair, data + offs, bfsize - offs, n - offs,
(struct sockaddr_ina *)&pair->in6);
2024-04-23 08:47:27 +03:00
}
else {
map_fix(&addr, 0);
2024-04-23 08:47:27 +03:00
memset(buffer, 0, S_SIZE_I6);
int offs = s5_set_addr(data, S_SIZE_I6, &addr, 1);
2024-04-23 08:47:27 +03:00
if (offs < 0 || offs > S_SIZE_I6) {
return -1;
}
2024-10-20 18:50:08 +03:00
ns = send(pair->fd, data - offs, offs + n, 0);
2024-04-23 08:47:27 +03:00
}
if (ns < 0) {
2024-05-04 22:57:38 +03:00
uniperror("sendto");
2024-04-23 08:47:27 +03:00
return -1;
}
} while(1);
return 0;
2024-04-16 20:55:41 +03:00
}
2024-03-11 18:38:39 +03:00
static inline int on_request(struct poolhd *pool, struct eval *val,
char *buffer, size_t bfsize)
{
struct sockaddr_ina dst = {0};
ssize_t n = recv(val->fd, buffer, bfsize, 0);
if (n < 1) {
if (n) uniperror("ss recv");
return -1;
}
2024-03-28 20:42:43 +03:00
int error = 0;
2024-03-11 18:38:39 +03:00
if (*buffer == S_VER5) {
if (val->flag != FLAG_S5) {
if (auth_socks5(val->fd, buffer, n)) {
return -1;
}
val->flag = FLAG_S5;
return 0;
}
2024-04-23 08:47:27 +03:00
if (n < S_SIZE_MIN) {
LOG(LOG_E, "ss: request too small (%zd)\n", n);
2024-04-16 20:55:41 +03:00
return -1;
}
2024-04-23 08:47:27 +03:00
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);
}
2024-04-04 04:19:40 +03:00
break;
2024-04-23 08:47:27 +03:00
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);
}
2024-04-16 20:55:41 +03:00
break;
}
2024-04-23 08:47:27 +03:00
default:
LOG(LOG_E, "ss: unsupported cmd: 0x%x\n", r->cmd);
s5e = -S_ER_CMD;
2024-03-11 18:38:39 +03:00
}
2024-04-23 08:47:27 +03:00
if (s5e < 0) {
if (resp_s5_error(val->fd, -s5e) < 0)
2024-05-04 22:57:38 +03:00
uniperror("send");
2024-03-11 18:38:39 +03:00
return -1;
2024-03-08 21:33:25 +03:00
}
2024-03-08 03:37:02 +03:00
}
2024-04-23 08:47:27 +03:00
else if (*buffer == S_VER4) {
val->flag = FLAG_S4;
2024-03-08 03:37:02 +03:00
2024-04-23 08:47:27 +03:00
error = s4_get_addr(buffer, n, &dst);
if (error) {
if (resp_error(val->fd, error, FLAG_S4) < 0)
2024-05-04 22:57:38 +03:00
uniperror("send");
2024-03-08 03:37:02 +03:00
return -1;
}
2024-04-23 08:47:27 +03:00
error = connect_hook(pool, val, &dst, EV_CONNECT);
2024-03-08 21:33:25 +03:00
}
else {
2024-08-07 14:44:12 +03:00
LOG(LOG_E, "ss: invalid version: 0x%x (%zd)\n", *buffer, n);
2024-03-13 22:18:16 +03:00
return -1;
}
2024-04-23 08:47:27 +03:00
if (error) {
int en = get_e();
if (resp_error(val->fd, en ? en : error, val->flag) < 0)
uniperror("send");
2024-07-18 23:59:44 +03:00
LOG(LOG_S, "ss error: %d\n", en);
2024-03-08 03:37:02 +03:00
return -1;
}
return 0;
}
2024-03-11 18:38:39 +03:00
static inline int on_connect(struct poolhd *pool, struct eval *val, int e)
2024-03-08 03:37:02 +03:00
{
int error = 0;
socklen_t len = sizeof(error);
if (e) {
if (getsockopt(val->fd, SOL_SOCKET,
SO_ERROR, (char *)&error, &len)) {
uniperror("getsockopt SO_ERROR");
return -1;
}
}
2024-03-11 18:38:39 +03:00
else {
if (mod_etype(pool, val, POLLIN) ||
mod_etype(pool, val->pair, POLLIN)) {
2024-03-11 18:38:39 +03:00
uniperror("mod_etype");
2024-03-08 03:37:02 +03:00
return -1;
}
2024-10-20 18:50:08 +03:00
int t = params.auto_level <= AUTO_NOBUFF
? EV_TUNNEL : EV_FIRST_TUNNEL;
val->type = t;
val->pair->type = t;
2024-03-08 03:37:02 +03:00
}
2024-03-12 02:53:57 +03:00
if (resp_error(val->pair->fd,
error, val->pair->flag) < 0) {
2024-03-11 18:38:39 +03:00
uniperror("send");
2024-03-08 03:37:02 +03:00
return -1;
}
2024-03-11 18:38:39 +03:00
return e ? -1 : 0;
}
2024-11-09 18:07:27 +03:00
static void close_conn(struct poolhd *pool, struct eval *val)
2024-07-18 23:59:44 +03:00
{
2024-10-20 18:50:08 +03:00
struct eval *cval = val;
do {
LOG(LOG_S, "close: fd=%d (pair=%d), recv: %zd, rounds: %d\n",
cval->fd, cval->pair ? cval->pair->fd : -1,
cval->recv_count, cval->round_count);
cval = cval->pair;
} while (cval && cval != val);
2024-07-18 23:59:44 +03:00
del_event(pool, val);
}
int event_loop(int srvfd)
2023-06-03 22:52:10 +03:00
{
size_t bfsize = params.bfsize;
struct poolhd *pool = init_pool(params.max_open * 2 + 1);
if (!pool) {
2024-02-27 00:52:59 +03:00
close(srvfd);
return -1;
}
if (!add_event(pool, EV_ACCEPT, srvfd, POLLIN)) {
2024-02-27 00:52:59 +03:00
destroy_pool(pool);
close(srvfd);
2023-06-03 22:52:10 +03:00
return -1;
}
char *buffer = malloc(params.bfsize);
if (!buffer) {
2024-03-02 14:14:02 +03:00
uniperror("malloc");
2024-02-27 00:52:59 +03:00
destroy_pool(pool);
2023-06-03 22:52:10 +03:00
return -1;
}
struct eval *val;
int i = -1, etype;
while (NOT_EXIT) {
val = next_event(pool, &i, &etype);
if (!val) {
2024-02-18 23:20:52 +03:00
if (get_e() == EINTR)
2023-06-03 22:52:10 +03:00
continue;
2024-02-18 23:20:52 +03:00
uniperror("(e)poll");
2023-06-03 22:52:10 +03:00
break;
}
assert(val->type >= 0
&& val->type < sizeof(eid_name)/sizeof(*eid_name));
LOG(LOG_L, "new event: fd: %d, evt: %s, mod_iter: %llu\n", val->fd, eid_name[val->type], val->mod_iter);
2024-05-04 19:42:19 +03:00
2023-06-03 22:52:10 +03:00
switch (val->type) {
case EV_ACCEPT:
2024-02-27 18:34:02 +03:00
if ((etype & POLLHUP) ||
on_accept(pool, val))
2023-06-03 22:52:10 +03:00
NOT_EXIT = 0;
continue;
case EV_REQUEST:
if ((etype & POLLHUP) ||
on_request(pool, val, buffer, bfsize))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2023-06-03 22:52:10 +03:00
continue;
2024-10-20 18:50:08 +03:00
case EV_FIRST_TUNNEL:
if (on_first_tunnel(pool, val, buffer, bfsize, etype))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2024-03-08 21:33:25 +03:00
continue;
2023-06-03 22:52:10 +03:00
case EV_TUNNEL:
2024-05-17 14:06:29 +03:00
if (on_tunnel(pool, val, buffer, bfsize, etype))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2023-06-03 22:52:10 +03:00
continue;
2024-04-23 08:47:27 +03:00
case EV_UDP_TUNNEL:
if (on_udp_tunnel(val, buffer, bfsize))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2024-04-23 08:47:27 +03:00
continue;
2023-06-03 22:52:10 +03:00
case EV_CONNECT:
2024-03-11 18:38:39 +03:00
if (on_connect(pool, val, etype & POLLERR))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2023-06-03 22:52:10 +03:00
continue;
case EV_IGNORE:
2023-07-06 21:21:44 +03:00
if (etype & (POLLHUP | POLLERR | POLLRDHUP))
2024-07-18 23:59:44 +03:00
close_conn(pool, val);
2023-06-03 22:52:10 +03:00
continue;
default:
2024-02-24 20:44:54 +03:00
LOG(LOG_E, "???\n");
2023-06-03 22:52:10 +03:00
NOT_EXIT = 0;
}
}
2024-02-27 18:34:02 +03:00
LOG(LOG_S, "exit\n");
2023-06-03 22:52:10 +03:00
free(buffer);
destroy_pool(pool);
return 0;
}
2024-11-09 18:07:27 +03:00
int listen_socket(const struct sockaddr_ina *srv)
2023-06-03 22:52:10 +03:00
{
2024-02-27 18:34:02 +03:00
int srvfd = nb_socket(srv->sa.sa_family, SOCK_STREAM);
2023-06-03 22:52:10 +03:00
if (srvfd < 0) {
2024-02-18 23:20:52 +03:00
uniperror("socket");
2023-06-03 22:52:10 +03:00
return -1;
}
int opt = 1;
if (setsockopt(srvfd, SOL_SOCKET,
SO_REUSEADDR, (char *)&opt, sizeof(opt)) == -1) {
2024-02-18 23:20:52 +03:00
uniperror("setsockopt");
2023-06-03 22:52:10 +03:00
close(srvfd);
return -1;
}
if (bind(srvfd, &srv->sa, SA_SIZE(srv)) < 0) {
2024-02-18 23:20:52 +03:00
uniperror("bind");
2023-06-03 22:52:10 +03:00
close(srvfd);
return -1;
}
if (listen(srvfd, 10)) {
2024-02-18 23:20:52 +03:00
uniperror("listen");
2023-06-03 22:52:10 +03:00
close(srvfd);
return -1;
}
2024-02-27 18:34:02 +03:00
return srvfd;
}
2024-11-09 18:07:27 +03:00
int run(const struct sockaddr_ina *srv)
2024-02-27 18:34:02 +03:00
{
#ifdef SIGPIPE
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
uniperror("signal SIGPIPE!");
#endif
signal(SIGINT, on_cancel);
2024-09-10 11:26:15 +03:00
signal(SIGTERM, on_cancel);
2024-02-27 18:34:02 +03:00
int fd = listen_socket(srv);
if (fd < 0) {
return -1;
}
return event_loop(fd);
}