mirror of
https://github.com/3proxy/3proxy.git
synced 2026-05-13 13:30:12 +08:00
SOCKSv5 parent udp support (initial, untested)
This commit is contained in:
parent
8107f03062
commit
314503d8df
@ -930,7 +930,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
if(udplen <= 0) continue;
|
if(udplen <= 0) continue;
|
||||||
_3proxy_sem_lock(udpinit);
|
_3proxy_sem_lock(udpinit);
|
||||||
if(hashresolv(&udp_table, &defparam, &toparam, NULL)) {
|
if(hashresolv(&udp_table, &defparam, &toparam, NULL)) {
|
||||||
socksendto(toparam, toparam->remsock, (struct sockaddr *)&toparam->sinsr, udpbuf, udplen, 0);
|
srv.so._sendto(toparam->sostate, toparam->remsock, (char *)udpbuf, udplen, 0, (struct sockaddr *)&toparam->sinsr, SASIZE(&toparam->sinsr));
|
||||||
_3proxy_sem_unlock(udpinit);
|
_3proxy_sem_unlock(udpinit);
|
||||||
toparam->statscli64 += udplen;
|
toparam->statscli64 += udplen;
|
||||||
toparam->nwrites++;
|
toparam->nwrites++;
|
||||||
|
|||||||
@ -132,6 +132,8 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
|
|||||||
case R_SOCKS5B:
|
case R_SOCKS5B:
|
||||||
{
|
{
|
||||||
int inbuf = 0;
|
int inbuf = 0;
|
||||||
|
int atyp;
|
||||||
|
int skip_port = 0;
|
||||||
buf[0] = 5;
|
buf[0] = 5;
|
||||||
buf[1] = 1;
|
buf[1] = 1;
|
||||||
buf[2] = user? 2 : 0;
|
buf[2] = user? 2 : 0;
|
||||||
@ -170,9 +172,14 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[0] = 5;
|
buf[0] = 5;
|
||||||
buf[1] = 1;
|
buf[1] = (param->operation == UDPASSOC && redir->type != R_SOCKS5B) ? 3 : 1;
|
||||||
buf[2] = 0;
|
buf[2] = 0;
|
||||||
if(redir->type == R_SOCKS5P && hostname) {
|
if (param->operation == UDPASSOC && redir->type != R_SOCKS5B) {
|
||||||
|
buf[3] = 1;
|
||||||
|
memset(buf + 4, 0, 6);
|
||||||
|
len = 10;
|
||||||
|
skip_port = 1;
|
||||||
|
} else if(redir->type == R_SOCKS5P && hostname) {
|
||||||
buf[3] = 3;
|
buf[3] = 3;
|
||||||
len = (int)strlen((char *)hostname);
|
len = (int)strlen((char *)hostname);
|
||||||
if(len > 255) len = 255;
|
if(len > 255) len = 255;
|
||||||
@ -186,8 +193,10 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
|
|||||||
memcpy(buf+len, SAADDR(addr), SAADDRLEN(addr));
|
memcpy(buf+len, SAADDR(addr), SAADDRLEN(addr));
|
||||||
len += SAADDRLEN(addr);
|
len += SAADDRLEN(addr);
|
||||||
}
|
}
|
||||||
memcpy(buf+len, SAPORT(addr), 2);
|
if (!skip_port) {
|
||||||
len += 2;
|
memcpy(buf+len, SAPORT(addr), 2);
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
if(socksend(param, param->remsock, buf, len, conf.timeouts[CHAIN_TO]) != len){
|
if(socksend(param, param->remsock, buf, len, conf.timeouts[CHAIN_TO]) != len){
|
||||||
return 51;
|
return 51;
|
||||||
}
|
}
|
||||||
@ -202,6 +211,7 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
|
|||||||
if(buf[1] != 0) {
|
if(buf[1] != 0) {
|
||||||
return 60 + (buf[1] % 10);
|
return 60 + (buf[1] % 10);
|
||||||
}
|
}
|
||||||
|
atyp = buf[3];
|
||||||
switch (buf[3]) {
|
switch (buf[3]) {
|
||||||
case 1:
|
case 1:
|
||||||
if (redir->type == R_SOCKS5B || sockgetlinebuf(param, SERVER, buf, 6, EOF, conf.timeouts[CHAIN_TO]) == 6)
|
if (redir->type == R_SOCKS5B || sockgetlinebuf(param, SERVER, buf, 6, EOF, conf.timeouts[CHAIN_TO]) == 6)
|
||||||
@ -219,6 +229,21 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
|
|||||||
default:
|
default:
|
||||||
return 58;
|
return 58;
|
||||||
}
|
}
|
||||||
|
if (param->operation == UDPASSOC && (redir->type == R_SOCKS5 || redir->type == R_SOCKS5P) && param->udp_nhops < 3) {
|
||||||
|
PROXYSOCKADDRTYPE *relay = ¶m->udp_relay[param->udp_nhops];
|
||||||
|
memset(relay, 0, sizeof(*relay));
|
||||||
|
if (atyp == 1) {
|
||||||
|
((struct sockaddr_in *)relay)->sin_family = AF_INET;
|
||||||
|
memcpy(&((struct sockaddr_in *)relay)->sin_addr, buf, 4);
|
||||||
|
memcpy(&((struct sockaddr_in *)relay)->sin_port, buf + 4, 2);
|
||||||
|
param->udp_nhops++;
|
||||||
|
} else if (atyp == 4) {
|
||||||
|
((struct sockaddr_in6 *)relay)->sin6_family = AF_INET6;
|
||||||
|
memcpy(&((struct sockaddr_in6 *)relay)->sin6_addr, buf, 16);
|
||||||
|
memcpy(&((struct sockaddr_in6 *)relay)->sin6_port, buf + 16, 2);
|
||||||
|
param->udp_nhops++;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
|
|||||||
int HASERROR=0;
|
int HASERROR=0;
|
||||||
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
|
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
|
||||||
int after = 0;
|
int after = 0;
|
||||||
struct pollfd fds[6];
|
struct pollfd fds[8];
|
||||||
struct pollfd *fdsp = fds;
|
struct pollfd *fdsp = fds;
|
||||||
int fdsc = 0;
|
int fdsc = 0;
|
||||||
int sleeptime = 0;
|
int sleeptime = 0;
|
||||||
@ -212,7 +212,7 @@ log("send to server from buf");
|
|||||||
param->clioffset = param->cliinbuf = 0;
|
param->clioffset = param->cliinbuf = 0;
|
||||||
if(fromclient) TOCLIENTBUF = 1;
|
if(fromclient) TOCLIENTBUF = 1;
|
||||||
}
|
}
|
||||||
sasize = sizeof(param->sinsr);
|
sasize = SASIZE(¶m->sinsr);
|
||||||
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, (struct sockaddr*)¶m->sinsr, sasize);
|
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, (struct sockaddr*)¶m->sinsr, sasize);
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOSERVER = 0;
|
TOSERVER = 0;
|
||||||
@ -258,7 +258,7 @@ log("send to client from buf");
|
|||||||
param->srvinbuf = param->srvoffset = 0;
|
param->srvinbuf = param->srvoffset = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sasize = sizeof(param->sincr);
|
sasize = SASIZE(¶m->sincr);
|
||||||
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, (struct sockaddr*)¶m->sincr, sasize);
|
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, (struct sockaddr*)¶m->sincr, sasize);
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOCLIENT = 0;
|
TOCLIENT = 0;
|
||||||
@ -706,6 +706,24 @@ log("ready reading from server pipe");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if(param->ctrlsock != INVALID_SOCKET) {
|
||||||
|
if(!after) {
|
||||||
|
fds[fdsc].fd = param->ctrlsock;
|
||||||
|
fds[fdsc].events = POLLIN;
|
||||||
|
} else if(fds[fdsc].revents) {
|
||||||
|
CLIENTTERMREAD = CLIENTTERMWRITE = SERVERTERMREAD = SERVERTERMWRITE = 1;
|
||||||
|
}
|
||||||
|
fdsc++;
|
||||||
|
}
|
||||||
|
if(param->ctrlsocksrv != INVALID_SOCKET) {
|
||||||
|
if(!after) {
|
||||||
|
fds[fdsc].fd = param->ctrlsocksrv;
|
||||||
|
fds[fdsc].events = POLLIN;
|
||||||
|
} else if(fds[fdsc].revents) {
|
||||||
|
CLIENTTERMREAD = CLIENTTERMWRITE = SERVERTERMREAD = SERVERTERMWRITE = 1;
|
||||||
|
}
|
||||||
|
fdsc++;
|
||||||
|
}
|
||||||
if(!after){
|
if(!after){
|
||||||
if(!fdsc) RETURN(90);
|
if(!fdsc) RETURN(90);
|
||||||
|
|
||||||
|
|||||||
107
src/socks.c
107
src/socks.c
@ -13,7 +13,6 @@
|
|||||||
unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONNECT", (unsigned char *)"BIND", (unsigned char *)"UDPMAP"};
|
unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONNECT", (unsigned char *)"BIND", (unsigned char *)"UDPMAP"};
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
#define BUFSIZE 1024
|
||||||
#define LARGEBUFSIZE 67000
|
|
||||||
|
|
||||||
#if SOCKSTRACE > 0
|
#if SOCKSTRACE > 0
|
||||||
char tracebuf[256];
|
char tracebuf[256];
|
||||||
@ -407,111 +406,7 @@ fflush(stderr);
|
|||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
param->sinsr = param->req;
|
param->sinsr = param->req;
|
||||||
myfree(buf);
|
param->res = udpsockmap(param, conf.timeouts[CONNECTION_L]);
|
||||||
if(!(buf = myalloc(LARGEBUFSIZE))) {RETURN(21);}
|
|
||||||
sin = param->sincr;
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
fds[0].fd = param->remsock;
|
|
||||||
fds[1].fd = param->clisock;
|
|
||||||
fds[2].fd = param->ctrlsock;
|
|
||||||
fds[2].events = fds[1].events = fds[0].events = POLLIN;
|
|
||||||
|
|
||||||
res = param->srv->so._poll(param->sostate, fds, 3, conf.timeouts[CONNECTION_L]*1000);
|
|
||||||
if(res <= 0) {
|
|
||||||
param->res = 463;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fds[2].revents) {
|
|
||||||
param->res = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fds[1].revents) {
|
|
||||||
sasize = sizeof(sin);
|
|
||||||
if((len = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) {
|
|
||||||
param->res = 464;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin))){
|
|
||||||
param->res = 465;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(buf[0] || buf[1] || buf[2]) {
|
|
||||||
param->res = 466;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size = 4;
|
|
||||||
switch(buf[3]) {
|
|
||||||
case 4:
|
|
||||||
size = 16;
|
|
||||||
case 1:
|
|
||||||
i = 4+size;
|
|
||||||
*SAFAMILY(¶m->sinsr) = (size == 4)?AF_INET:AF_INET6;
|
|
||||||
memcpy(SAADDR(¶m->sinsr), buf+4, size);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
size = buf[4];
|
|
||||||
for (i=4; size; i++, size--){
|
|
||||||
buf[i] = buf[i+1];
|
|
||||||
}
|
|
||||||
buf[i++] = 0;
|
|
||||||
if(!getip46(param->srv->family, buf+4, (struct sockaddr *) ¶m->sinsr)) RETURN(100);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
RETURN(997);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(SAPORT(¶m->sinsr), buf+i, 2);
|
|
||||||
i+=2;
|
|
||||||
|
|
||||||
sasize = sizeof(param->sinsr);
|
|
||||||
if(len > (int)i){
|
|
||||||
socksendto(param, param->remsock, (struct sockaddr *)¶m->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000);
|
|
||||||
param->statscli64+=(len - i);
|
|
||||||
param->nwrites++;
|
|
||||||
#if SOCKSTRACE > 1
|
|
||||||
myinet_ntop(*SAFAMILY(¶m->sinsr), ¶m->sinsr, tracebuf, SASIZE(¶m->sinsr));
|
|
||||||
|
|
||||||
fprintf(stderr, "UDP packet relayed from client to %s:%hu size %d, header %d\n",
|
|
||||||
tracebuf,
|
|
||||||
ntohs(*SAPORT(¶m->sinsr)),
|
|
||||||
(len - i),
|
|
||||||
i
|
|
||||||
);
|
|
||||||
myinet_ntop(*SAFAMILY(&sin), &sin, tracebuf, SASIZE(&sin));
|
|
||||||
fprintf(stderr, "client address is assumed to be %s:%hu\n",
|
|
||||||
tracebuf,
|
|
||||||
ntohs(*SAPORT(&sin))
|
|
||||||
);
|
|
||||||
fflush(stderr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (fds[0].revents) {
|
|
||||||
sasize = sizeof(param->sinsr);
|
|
||||||
buf[0]=buf[1]=buf[2]=0;
|
|
||||||
buf[3]=(*SAFAMILY(¶m->sinsl) == AF_INET)?1:4;
|
|
||||||
if((len = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)buf+6+SAADDRLEN(¶m->sinsl), 65535 - (6+SAADDRLEN(¶m->sinsl)), 0, (struct sockaddr *)¶m->sinsr, &sasize)) <= 0) {
|
|
||||||
param->res = 468;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
param->statssrv64+=len;
|
|
||||||
param->nreads++;
|
|
||||||
memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
|
|
||||||
memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
|
|
||||||
sasize = sizeof(sin);
|
|
||||||
socksendto(param, param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(¶m->sinsr), conf.timeouts[SINGLEBYTE_L]*1000);
|
|
||||||
#if SOCKSTRACE > 1
|
|
||||||
fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
|
|
||||||
ntohs(*SAPORT(¶m->sinsr)),
|
|
||||||
len
|
|
||||||
);
|
|
||||||
fflush(stderr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
param->res = 417;
|
param->res = 417;
|
||||||
|
|||||||
@ -53,14 +53,15 @@ void * udppmchild(struct clientparam* param) {
|
|||||||
authres = (*param->srv->authfunc)(param);
|
authres = (*param->srv->authfunc)(param);
|
||||||
if(authres) { RETURN(authres); }
|
if(authres) { RETURN(authres); }
|
||||||
if(!param->srv->singlepacket)hashadd(&udp_table, param, ¶m, MAX_COUNTER_TIME);
|
if(!param->srv->singlepacket)hashadd(&udp_table, param, ¶m, MAX_COUNTER_TIME);
|
||||||
socksendto(param, param->remsock, (struct sockaddr *)¶m->sinsr, param->srvbuf, param->srvinbuf, 0);
|
param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, param->srvinbuf, 0, (struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr));
|
||||||
_3proxy_sem_unlock(udpinit);
|
_3proxy_sem_unlock(udpinit);
|
||||||
param->statscli64 += param->srvinbuf;
|
param->statscli64 += param->srvinbuf;
|
||||||
param->srvinbuf = 0;
|
param->srvinbuf = 0;
|
||||||
param->nwrites++;
|
param->nwrites++;
|
||||||
param->clisock = param->srv->srvsock;
|
param->clisock = param->srv->srvsock;
|
||||||
|
param->udp_nhops = 1;
|
||||||
param->waitserver64 = 0x7fffffffffffffff;
|
param->waitserver64 = 0x7fffffffffffffff;
|
||||||
param->res = mapsocket(param, conf.timeouts[STRING_L]);
|
param->res = udpsockmap(param, conf.timeouts[STRING_L]);
|
||||||
_3proxy_sem_lock(udpinit);
|
_3proxy_sem_lock(udpinit);
|
||||||
if(!param->srv->singlepacket)hashdelete(&udp_table, param);
|
if(!param->srv->singlepacket)hashdelete(&udp_table, param);
|
||||||
|
|
||||||
|
|||||||
215
src/udpsockmap.c
Normal file
215
src/udpsockmap.c
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
3APA3A simplest proxy server
|
||||||
|
(c) 2002-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
|
||||||
|
|
||||||
|
please read License Agreement
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proxy.h"
|
||||||
|
|
||||||
|
static int socks5_udp_build_hdr(unsigned char *buf, PROXYSOCKADDRTYPE *addr)
|
||||||
|
{
|
||||||
|
buf[0] = buf[1] = buf[2] = 0;
|
||||||
|
buf[3] = (*SAFAMILY(addr) == AF_INET) ? 1 : 4;
|
||||||
|
memcpy(buf + 4, SAADDR(addr), SAADDRLEN(addr));
|
||||||
|
memcpy(buf + 4 + SAADDRLEN(addr), SAPORT(addr), 2);
|
||||||
|
return 4 + SAADDRLEN(addr) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socks5_udp_skip_hdr(unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
int addr_len;
|
||||||
|
if (len < 4) return -1;
|
||||||
|
switch (buf[3]) {
|
||||||
|
case 1: addr_len = 4; break;
|
||||||
|
case 4: addr_len = 16; break;
|
||||||
|
case 3:
|
||||||
|
if (len < 5) return -1;
|
||||||
|
addr_len = 1 + (unsigned char)buf[4];
|
||||||
|
break;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
int off = 4 + addr_len + 2;
|
||||||
|
return (off <= len) ? off : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* udpsockmap: bidirectional UDP relay.
|
||||||
|
*
|
||||||
|
* param->udp_nhops selects the relay mode:
|
||||||
|
* 0 direct SOCKS5 relay (strip/add headers)
|
||||||
|
* 1 one parent SOCKS5 proxy (pass datagrams unchanged)
|
||||||
|
* 2 two parent proxies (prepend 1 header / strip 1 header)
|
||||||
|
* 3 three parent proxies (prepend 2 headers / strip 2 headers)
|
||||||
|
*
|
||||||
|
* param->waitserver64 non-zero: skip client socket polling (server→client only)
|
||||||
|
* param->srv->singlepacket non-zero: return after first datagram sent to client
|
||||||
|
* param->ctrlsock TCP control socket from the client; INVALID_SOCKET if none.
|
||||||
|
*/
|
||||||
|
int udpsockmap(struct clientparam *param, int timeo)
|
||||||
|
{
|
||||||
|
PROXYSOCKADDRTYPE sin;
|
||||||
|
PROXYSOCKADDRTYPE from;
|
||||||
|
struct pollfd fds[4];
|
||||||
|
SASIZETYPE sasize;
|
||||||
|
int len, res, nfds;
|
||||||
|
int nhops = param->udp_nhops;
|
||||||
|
int clisock_idx = -1, ctrlsock_idx = -1, ctrlsocksrv_idx = -1;
|
||||||
|
int firstpacket = 1;
|
||||||
|
|
||||||
|
if (param->srvbufsize < UDPBUFSIZE) {
|
||||||
|
unsigned char *newbuf = myrealloc(param->srvbuf, UDPBUFSIZE);
|
||||||
|
if (!newbuf) return 21;
|
||||||
|
param->srvbuf = newbuf;
|
||||||
|
param->srvbufsize = UDPBUFSIZE;
|
||||||
|
}
|
||||||
|
sin = param->sincr;
|
||||||
|
|
||||||
|
/* Build poll array once — sockets don't change across iterations */
|
||||||
|
nfds = 0;
|
||||||
|
fds[nfds].fd = param->remsock; /* always index 0 */
|
||||||
|
fds[nfds].events = POLLIN;
|
||||||
|
nfds++;
|
||||||
|
|
||||||
|
if (!param->waitserver64) {
|
||||||
|
fds[nfds].fd = param->clisock;
|
||||||
|
fds[nfds].events = POLLIN;
|
||||||
|
clisock_idx = nfds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->ctrlsock != INVALID_SOCKET) {
|
||||||
|
fds[nfds].fd = param->ctrlsock;
|
||||||
|
fds[nfds].events = POLLIN;
|
||||||
|
ctrlsock_idx = nfds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->ctrlsocksrv != INVALID_SOCKET) {
|
||||||
|
fds[nfds].fd = param->ctrlsocksrv;
|
||||||
|
fds[nfds].events = POLLIN;
|
||||||
|
ctrlsocksrv_idx = nfds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
res = param->srv->so._poll(param->sostate, fds, nfds, timeo * 1000);
|
||||||
|
if (res < 0) return 463;
|
||||||
|
if (res == 0) return 92;
|
||||||
|
|
||||||
|
/* datagram from client */
|
||||||
|
if (clisock_idx >= 0 && fds[clisock_idx].revents) {
|
||||||
|
int recvoff = 0, k;
|
||||||
|
sasize = sizeof(sin);
|
||||||
|
for (k = 1; k < nhops; k++)
|
||||||
|
recvoff += 4 + (int)SAADDRLEN(¶m->udp_relay[k]) + 2;
|
||||||
|
len = param->srv->so._recvfrom(param->sostate, param->clisock,
|
||||||
|
(char *)param->srvbuf + recvoff, UDPBUFSIZE - recvoff,
|
||||||
|
0, (struct sockaddr *)&sin, &sasize);
|
||||||
|
if (len <= 0) return 464;
|
||||||
|
|
||||||
|
if (SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) ||
|
||||||
|
memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin)))
|
||||||
|
continue;
|
||||||
|
if (firstpacket) {
|
||||||
|
param->sincr = sin;
|
||||||
|
firstpacket = 0;
|
||||||
|
} else if (memcmp(SAPORT(&sin), SAPORT(¶m->sincr), 2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nhops == 0) {
|
||||||
|
int i;
|
||||||
|
if (len < 10 || param->srvbuf[0] || param->srvbuf[1] || param->srvbuf[2])
|
||||||
|
return 466;
|
||||||
|
switch (param->srvbuf[3]) {
|
||||||
|
case 1:
|
||||||
|
*SAFAMILY(¶m->sinsr) = AF_INET;
|
||||||
|
memcpy(SAADDR(¶m->sinsr), param->srvbuf + 4, 4);
|
||||||
|
i = 8;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (len < 22) return 466;
|
||||||
|
*SAFAMILY(¶m->sinsr) = AF_INET6;
|
||||||
|
memcpy(SAADDR(¶m->sinsr), param->srvbuf + 4, 16);
|
||||||
|
i = 20;
|
||||||
|
break;
|
||||||
|
case 3: {
|
||||||
|
int sz = param->srvbuf[4], j;
|
||||||
|
if (len < 7 + sz) return 466;
|
||||||
|
for (j = 4; j < 4 + sz; j++) param->srvbuf[j] = param->srvbuf[j + 1];
|
||||||
|
param->srvbuf[4 + sz] = 0;
|
||||||
|
i = 5 + sz;
|
||||||
|
if (!getip46(param->srv->family, param->srvbuf + 4,
|
||||||
|
(struct sockaddr *)¶m->sinsr))
|
||||||
|
return 100;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return 997;
|
||||||
|
}
|
||||||
|
memcpy(SAPORT(¶m->sinsr), param->srvbuf + i, 2);
|
||||||
|
i += 2;
|
||||||
|
if (len > i) {
|
||||||
|
param->srv->so._sendto(param->sostate, param->remsock,
|
||||||
|
(char *)param->srvbuf + i, len - i, 0,
|
||||||
|
(struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr));
|
||||||
|
param->statscli64 += (len - i);
|
||||||
|
param->nwrites++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int off = 0;
|
||||||
|
for (k = 1; k < nhops; k++)
|
||||||
|
off += socks5_udp_build_hdr(param->srvbuf + off, ¶m->udp_relay[k]);
|
||||||
|
param->srv->so._sendto(param->sostate, param->remsock,
|
||||||
|
(char *)param->srvbuf, off + len, 0,
|
||||||
|
(struct sockaddr *)¶m->udp_relay[0], SASIZE(¶m->udp_relay[0]));
|
||||||
|
param->statscli64 += len;
|
||||||
|
param->nwrites++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* datagram from server / parent relay */
|
||||||
|
if (fds[0].revents) {
|
||||||
|
int hdrsize = (nhops == 0) ? 4 + (int)SAADDRLEN(¶m->sinsr) + 2 : 0;
|
||||||
|
int sendoff = 0, sendlen;
|
||||||
|
sasize = sizeof(from);
|
||||||
|
if (hdrsize > UDPBUFSIZE) return 468;
|
||||||
|
len = param->srv->so._recvfrom(param->sostate, param->remsock,
|
||||||
|
(char *)param->srvbuf + hdrsize, UDPBUFSIZE - hdrsize, 0,
|
||||||
|
(struct sockaddr *)&from, &sasize);
|
||||||
|
if (len <= 0) return 468;
|
||||||
|
if (!SAISNULL(¶m->sinsr) && *SAPORT(¶m->sinsr)) {
|
||||||
|
if (SAADDRLEN(&from) != SAADDRLEN(¶m->sinsr) ||
|
||||||
|
memcmp(SAADDR(&from), SAADDR(¶m->sinsr), SAADDRLEN(&from)) ||
|
||||||
|
memcmp(SAPORT(&from), SAPORT(¶m->sinsr), 2))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
param->statssrv64 += len;
|
||||||
|
param->nreads++;
|
||||||
|
sendlen = len;
|
||||||
|
if (nhops == 0) {
|
||||||
|
param->srvbuf[0] = param->srvbuf[1] = param->srvbuf[2] = 0;
|
||||||
|
param->srvbuf[3] = (*SAFAMILY(¶m->sinsr) == AF_INET) ? 1 : 4;
|
||||||
|
memcpy(param->srvbuf + 4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr));
|
||||||
|
memcpy(param->srvbuf + 4 + SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2);
|
||||||
|
sendlen = len + hdrsize;
|
||||||
|
} else if (nhops >= 2) {
|
||||||
|
int off = 0, k;
|
||||||
|
for (k = 1; k < nhops; k++) {
|
||||||
|
int next = socks5_udp_skip_hdr(param->srvbuf + off, len - off);
|
||||||
|
if (next < 0) break;
|
||||||
|
off += next;
|
||||||
|
}
|
||||||
|
sendoff = off;
|
||||||
|
sendlen = len - off;
|
||||||
|
}
|
||||||
|
if (sendlen > 0)
|
||||||
|
param->srv->so._sendto(param->sostate, param->clisock,
|
||||||
|
(char *)param->srvbuf + sendoff, sendlen, 0,
|
||||||
|
(struct sockaddr *)&sin, SASIZE(&sin));
|
||||||
|
if (param->srv->singlepacket) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ctrlsock_idx >= 0 && fds[ctrlsock_idx].revents) ||
|
||||||
|
(ctrlsocksrv_idx >= 0 && fds[ctrlsocksrv_idx].revents)) return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user