This commit is contained in:
ruti 2023-07-07 15:26:04 +02:00
parent 6248f8d705
commit cd0b7b14ed
2 changed files with 114 additions and 71 deletions

View File

@ -52,6 +52,10 @@ struct eval {
ssize_t size; ssize_t size;
int offset; int offset;
int flag; int flag;
union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
};
#ifndef NOEPOLL #ifndef NOEPOLL
uint32_t events; uint32_t events;
#endif #endif

171
proxy.c
View File

@ -29,6 +29,66 @@ static void on_cancel(int sig) {
} }
static inline int ip_cmp(
struct sockaddr_ina *a, struct sockaddr_ina *b)
{
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 void map_fix(struct sockaddr_ina *addr, int f6)
{
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;
}
else if (ipv6m->o64 == 0 && ipv6m->t16 == 0xffff && !f6) {
addr->sa.sa_family = AF_INET;
addr->in.sin_addr = *(struct in_addr *)(&ipv6m->o32);
}
}
static inline int nb_socket(int domain, int type) {
#ifdef __linux__
int fd = socket(domain, type | SOCK_NONBLOCK, 0);
#else
int fd = socket(domain, type, 0);
#endif
if (fd < 0) {
perror("socket");
return -1;
}
#ifndef __linux__
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
perror("fcntl");
close(fd);
return -1;
}
#endif
return fd;
}
int resolve(char *host, int len, int resolve(char *host, int len,
struct sockaddr_ina *addr, int type) struct sockaddr_ina *addr, int type)
{ {
@ -131,13 +191,13 @@ int handle_socks4(int fd, char *bf,
if (!ie) if (!ie)
break; break;
int len = (bf + n - ie) - 2; int len = (bf + n - ie) - 2;
if (len > 2) { if (len < 3)
break;
if (resolve(ie + 1, len, dst, SOCK_STREAM)) { if (resolve(ie + 1, len, dst, SOCK_STREAM)) {
fprintf(stderr, "not resolved: %.*s\n", len, ie + 1); fprintf(stderr, "not resolved: %.*s\n", len, ie + 1);
break; break;
} }
er = 0; er = 0;
}
} while (0); } while (0);
else { else {
dst->in.sin_family = AF_INET; dst->in.sin_family = AF_INET;
@ -156,7 +216,8 @@ int handle_socks4(int fd, char *bf,
} }
int s_get_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr) int s_get_addr(char *buffer, ssize_t n,
struct sockaddr_ina *addr, int type)
{ {
struct s5_req *r = (struct s5_req *)buffer; struct s5_req *r = (struct s5_req *)buffer;
@ -179,8 +240,9 @@ int s_get_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr)
} }
if (r->id.len == 1) { if (r->id.len == 1) {
addr->in.sin_family = AF_INET; addr->in.sin_family = AF_INET;
LOG(LOG_S, "domain len=1\n");
} }
else if (resolve(r->id.domain, r->id.len, addr, SOCK_STREAM)) { else if (resolve(r->id.domain, r->id.len, addr, type)) {
fprintf(stderr, "not resolved: %.*s\n", r->id.len, r->id.domain); fprintf(stderr, "not resolved: %.*s\n", r->id.len, r->id.domain);
return -S_ER_HOST; return -S_ER_HOST;
} }
@ -199,13 +261,17 @@ int s_get_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr)
} }
int s_set_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr) int s_set_addr(char *buffer, ssize_t n,
struct sockaddr_ina *addr, char end)
{ {
struct s5_req *r = (struct s5_req *)buffer; struct s5_req *r = (struct s5_req *)buffer;
if (n < S_SIZE_I4) { if (n < S_SIZE_I4) {
return -1; return -1;
} }
if (addr->sa.sa_family == AF_INET) { if (addr->sa.sa_family == AF_INET) {
if (end) {
r = (struct s5_req *)(buffer - S_SIZE_I4);
}
r->atp = S_ATP_I4; r->atp = S_ATP_I4;
r->i4 = addr->in.sin_addr; r->i4 = addr->in.sin_addr;
r->p4 = addr->in.sin_port; r->p4 = addr->in.sin_port;
@ -214,6 +280,9 @@ int s_set_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr)
if (n < S_SIZE_I6) { if (n < S_SIZE_I6) {
return -1; return -1;
} }
if (end) {
r = (struct s5_req *)(buffer - S_SIZE_I6);
}
r->atp = S_ATP_I6; r->atp = S_ATP_I6;
r->i6 = addr->in6.sin6_addr; r->i6 = addr->in6.sin6_addr;
r->p6 = addr->in6.sin6_port; r->p6 = addr->in6.sin6_port;
@ -222,27 +291,6 @@ int s_set_addr(char *buffer, ssize_t n, struct sockaddr_ina *addr)
} }
static inline int nb_socket(int domain, int type) {
#ifdef __linux__
int fd = socket(domain, type | SOCK_NONBLOCK, 0);
#else
int fd = socket(domain, type, 0);
#endif
if (fd < 0) {
perror("socket");
return -1;
}
#ifndef __linux__
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
perror("fcntl");
close(fd);
return -1;
}
#endif
return fd;
}
static inline int create_conn(struct poolhd *pool, struct eval *val, static inline int create_conn(struct poolhd *pool, struct eval *val,
enum eid nxt, struct sockaddr_ina *dst) enum eid nxt, struct sockaddr_ina *dst)
{ {
@ -294,24 +342,16 @@ static inline int create_conn(struct poolhd *pool, struct eval *val,
int udp_asc(struct poolhd *pool, int udp_asc(struct poolhd *pool,
struct eval *val, struct sockaddr_ina *dst) struct eval *val, struct sockaddr_ina *dst)
{ {
int ufd = nb_socket(dst->sa.sa_family, SOCK_DGRAM); int ufd = nb_socket(AF_INET6, SOCK_DGRAM);
if (ufd < 0) { if (ufd < 0) {
perror("socket"); perror("socket");
return -1; return -1;
} }
struct sockaddr_ina addr = {0}; struct sockaddr_ina addr = {0};
socklen_t asz = sizeof(addr); socklen_t asz = sizeof(addr);
int ip_is_set = ip_cmp(dst, &addr);
if (getsockname(val->fd, &addr.sa, &asz)) { addr.sa.sa_family = AF_INET6;
perror("getsockname");
close(ufd);
return -1;
}
if (addr.sa.sa_family == AF_INET)
addr.in.sin_port = 0;
else
addr.in6.sin6_port = 0;
if (bind(ufd, &addr.sa, sizeof(addr)) < 0) { if (bind(ufd, &addr.sa, sizeof(addr)) < 0) {
perror("bind"); perror("bind");
close(ufd); close(ufd);
@ -327,26 +367,21 @@ int udp_asc(struct poolhd *pool,
close(ufd); close(ufd);
return -1; return -1;
} }
upair->flag |= FLAG_CONN; upair->in6 = dst->in6;
int utfd = nb_socket(dst->sa.sa_family, SOCK_DGRAM); if (!ip_is_set) {
if (utfd < 0) { if (dst->sa.sa_family == AF_INET)
del_event(pool, upair); upair->in.sin_addr = val->in.sin_addr;
return -1; else
} upair->in6.sin6_addr = val->in6.sin6_addr;
struct eval *utpair = add_event(pool, EV_UDP_TUNNEL, utfd, POLLIN);
if (!utpair) {
close(utfd);
del_event(pool, upair);
return -1;
} }
map_fix((struct sockaddr_ina *)&upair->in6, 6);
val->pair = upair; val->pair = upair;
upair->pair = utpair; upair->pair = val;
utpair->pair = upair;
struct s5_req s5r = { struct s5_req s5r = {
.ver = 0x05 .ver = 0x05
}; };
int offs = s_set_addr((char *)&s5r, sizeof(s5r), &addr); int offs = s_set_addr((char *)&s5r, sizeof(s5r), &addr, 0);
if (offs < 0) { if (offs < 0) {
return -1; return -1;
} }
@ -383,7 +418,7 @@ static inline int on_request(struct poolhd *pool, struct eval *val,
} }
struct s5_req *r = (struct s5_req *)buffer; struct s5_req *r = (struct s5_req *)buffer;
int offs = s_get_addr(buffer, n, &dst); int offs = s_get_addr(buffer, n, &dst, SOCK_STREAM);
if (offs > 0) { if (offs > 0) {
if (r->cmd == S_CMD_AUDP) { if (r->cmd == S_CMD_AUDP) {
s = udp_asc(pool, val, &dst); s = udp_asc(pool, val, &dst);
@ -463,6 +498,7 @@ static inline int on_accept(struct poolhd *pool, struct eval *val)
close(c); close(c);
continue; continue;
} }
rval->in6 = client.in6;
} }
return 0; return 0;
} }
@ -580,10 +616,7 @@ static inline int on_tunnel(struct poolhd *pool, struct eval *val,
int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize) int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
{ {
struct sockaddr_ina addr; struct sockaddr_ina addr;
int skip = 0, offs; int skip = S_SIZE_I4, offs;
if (!(val->flag & FLAG_CONN)) {
skip = S_SIZE_I6;
}
do { do {
socklen_t asz = sizeof(addr); socklen_t asz = sizeof(addr);
ssize_t n = recvfrom(val->fd, buffer + skip, ssize_t n = recvfrom(val->fd, buffer + skip,
@ -595,24 +628,30 @@ int on_udp_tunnel(struct eval *val, char *buffer, size_t bfsize)
perror("recv udp"); perror("recv udp");
return -1; return -1;
} }
if (val->flag & FLAG_CONN) {
if (connect(val->fd, &addr.sa, sizeof(addr)) < 0) { if (!val->in6.sin6_port) {
perror("connect"); val->in6.sin6_port = addr.in6.sin6_port;
return -1;
} }
offs = s_get_addr(buffer, n, &addr); if (!ip_cmp((struct sockaddr_ina *)&val->in6, &addr) &&
addr.in6.sin6_port == val->in6.sin6_port) {
if (buffer[skip + 2]) { // frag
return 0;
}
offs = s_get_addr(buffer + skip, n, &addr, SOCK_DGRAM);
if (offs < 0) { if (offs < 0) {
return -1; return -1;
} }
ns = sendto(val->pair->fd, map_fix(&addr, 6);
buffer + offs, n - offs, 0, &addr.sa, asz); ns = sendto(val->fd,
buffer + skip + offs, n - offs, 0, &addr.sa, asz);
} else { } else {
offs = s_set_addr(buffer, skip, &addr); map_fix(&addr, 0);
offs = s_set_addr(buffer + skip, skip, &addr, 1);
if (offs < 0 || offs > skip) { if (offs < 0 || offs > skip) {
return -1; return -1;
} }
ns = send(val->pair->fd, ns = sendto(val->fd, buffer + skip - offs,
buffer + skip - offs, n + offs, 0); n + offs, 0, (struct sockaddr *)&val->in6, sizeof(val->in6));
} }
if (ns <= 0) { if (ns <= 0) {
perror("sendto"); perror("sendto");