Compare commits

..

5 Commits

Author SHA1 Message Date
Vladimir Dubrovin
07c1dc1462 Fix shutdown for Windows
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
2026-05-01 19:26:39 +03:00
Vladimir Dubrovin
acce67a512 Fix NULL address request for UDP ASSOC 2026-05-01 17:26:06 +03:00
Vladimir Dubrovin
e986f8a747 FIx hanging connections in sockmap 2026-05-01 17:19:23 +03:00
Vladimir Dubrovin
314503d8df SOCKSv5 parent udp support (initial, untested) 2026-05-01 15:13:53 +03:00
Vladimir Dubrovin
8107f03062 Move PCRE/SSL to main code 2026-05-01 15:11:08 +03:00
12 changed files with 321 additions and 124 deletions

1
.gitignore vendored
View File

@ -267,3 +267,4 @@ bin/3proxy_socks
bin/3proxy_tcppm
bin/3proxy_tlspr
bin/3proxy_udppm
build*/*

View File

@ -374,6 +374,10 @@ target_include_directories(srvudppm_obj PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# UDP socket relay (used by 3proxy, socks, udppm)
add_library(udpsockmap_obj OBJECT src/udpsockmap.c)
target_include_directories(udpsockmap_obj PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
# mainfunc object (proxymain.c compiled with MODULEMAINFUNC=mainfunc for 3proxy)
add_library(mainfunc OBJECT src/proxymain.c)
target_include_directories(mainfunc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
@ -402,6 +406,7 @@ add_executable(3proxy
$<TARGET_OBJECTS:srvudppm_obj>
$<TARGET_OBJECTS:mainfunc>
$<TARGET_OBJECTS:common_obj>
$<TARGET_OBJECTS:udpsockmap_obj>
$<TARGET_OBJECTS:base64_obj>
$<TARGET_OBJECTS:ftp_obj>
$<TARGET_OBJECTS:3proxy_crypt_obj>
@ -567,6 +572,10 @@ foreach(PROXY_NAME proxy socks pop3p smtpp ftppr tcppm udppm tlspr)
if(PROXY_NAME STREQUAL "udppm")
target_sources(${PROXY_NAME} PRIVATE src/hash.c)
endif()
if(PROXY_NAME STREQUAL "socks" OR PROXY_NAME STREQUAL "udppm")
target_sources(${PROXY_NAME} PRIVATE src/udpsockmap.c)
endif()
endforeach()
# Plugin output directory

View File

@ -39,11 +39,11 @@ ifeq ($(OPENSSL_CHECK), true)
CFLAGS += -DWITH_SSL
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
endif
PCRE_CHECK = $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
PCRE_CHECK = $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -lpcre2-8 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
ifeq ($(PCRE_CHECK), true)
CFLAGS += -DWITH_PCRE
PCRE_OBJS = pcre$(OBJSUFFICS)
PCRE_LIBS = -Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic
PCRE_LIBS = -lpcre2-8
endif
PAM_CHECK = $(shell echo "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
ifeq ($(PAM_CHECK), true)

View File

@ -7,6 +7,9 @@ all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)$(CRYPT_PREFIX)crypt$(EXESUFFICS)
sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h
$(CC) $(CFLAGS) sockmap.c
udpsockmap$(OBJSUFFICS): udpsockmap.c proxy.h structures.h
$(CC) $(COUT)udpsockmap$(OBJSUFFICS) $(CFLAGS) udpsockmap.c
common$(OBJSUFFICS): common.c proxy.h structures.h
$(CC) $(CFLAGS) common.c
@ -65,14 +68,14 @@ $(BUILDDIR)$(PREFIX)smtpp$(EXESUFFICS): sockmap$(OBJSUFFICS) smtpp$(OBJSUFFICS)
$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS): sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) ftp$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(COMPATLIBS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)ftppr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) ftppr$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) ftp$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)
$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)socks$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) hash$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) hash$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)$(PREFIX)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
@ -170,6 +173,6 @@ ssl$(OBJSUFFICS): ssl.c
pcre$(OBJSUFFICS): pcre.c
$(CC) $(COUT)pcre$(OBJSUFFICS) $(CFLAGS) $(DEFINEOPTION)WITH_PCRE pcre.c
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(VERSIONDEP)
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) blake2$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(VERSIONDEP)
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) acl$(OBJSUFFICS) limiter$(OBJSUFFICS) redirect$(OBJSUFFICS) authradius$(OBJSUFFICS) hash$(OBJSUFFICS) hashtables$(OBJSUFFICS) resolve$(OBJSUFFICS) sql$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) udpsockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) 3proxy_crypt$(OBJSUFFICS) blake2$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(SSL_OBJS) $(PCRE_OBJS) $(COMPATLIBS) $(LIBS) $(PCRE_LIBS)

View File

@ -51,6 +51,8 @@
#include <process.h>
#define SASIZETYPE int
#define SHUT_RDWR SD_BOTH
#define SHUT_WR SD_SEND
#define SHUT_RD SD_RECEIVE
#else
#ifndef FD_SETSIZE
#define FD_SETSIZE 4096
@ -175,6 +177,7 @@ extern struct extparam conf;
extern int timeouts[12];
int sockmap(struct clientparam * param, int timeo, int usesplice);
int udpsockmap(struct clientparam * param, int timeo);
int socksend(struct clientparam *param, SOCKET sock, unsigned char * buf, int bufsize, int to);
int socksendto(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);
int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin, unsigned char * buf, int bufsize, int to);

View File

@ -930,7 +930,7 @@ int MODULEMAINFUNC (int argc, char** argv){
if(udplen <= 0) continue;
_3proxy_sem_lock(udpinit);
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);
toparam->statscli64 += udplen;
toparam->nwrites++;

View File

@ -132,6 +132,8 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
case R_SOCKS5B:
{
int inbuf = 0;
int atyp;
int skip_port = 0;
buf[0] = 5;
buf[1] = 1;
buf[2] = user? 2 : 0;
@ -170,9 +172,14 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
}
}
buf[0] = 5;
buf[1] = 1;
buf[1] = (param->operation == UDPASSOC && redir->type != R_SOCKS5B) ? 3 : 1;
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;
len = (int)strlen((char *)hostname);
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));
len += SAADDRLEN(addr);
}
memcpy(buf+len, SAPORT(addr), 2);
len += 2;
if (!skip_port) {
memcpy(buf+len, SAPORT(addr), 2);
len += 2;
}
if(socksend(param, param->remsock, buf, len, conf.timeouts[CHAIN_TO]) != len){
return 51;
}
@ -202,6 +211,7 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
if(buf[1] != 0) {
return 60 + (buf[1] % 10);
}
atyp = buf[3];
switch (buf[3]) {
case 1:
if (redir->type == R_SOCKS5B || sockgetlinebuf(param, SERVER, buf, 6, EOF, conf.timeouts[CHAIN_TO]) == 6)
@ -219,6 +229,23 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
default:
return 58;
}
if (param->operation == UDPASSOC && (redir->type == R_SOCKS5 || redir->type == R_SOCKS5P) && param->udp_nhops < 3) {
PROXYSOCKADDRTYPE *relay = &param->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);
if (param->udp_nhops == 0) param->sinsr = *relay;
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);
if (param->udp_nhops == 0) param->sinsr = *relay;
param->udp_nhops++;
}
}
return 0;
}
@ -242,7 +269,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
if(param->remsock != INVALID_SOCKET) {
return 0;
}
if(SAISNULL(&param->req) || !*SAPORT(&param->req)) {
if((SAISNULL(&param->req) || !*SAPORT(&param->req)) && param->operation != UDPASSOC) {
return 100;
}

View File

@ -52,7 +52,7 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
int HASERROR=0;
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
int after = 0;
struct pollfd fds[6];
struct pollfd fds[8];
struct pollfd *fdsp = fds;
int fdsc = 0;
int sleeptime = 0;
@ -499,6 +499,14 @@ log("done read from server to buf");
}
}
}
if (CLIENTTERMREAD && !inclientbuf && !SERVERTERMWRITE) {
SERVERTERMWRITE = 1;
param->srv->so._shutdown(param->sostate, param->remsock, SHUT_WR);
}
if (SERVERTERMREAD && !inserverbuf && !CLIENTTERMWRITE) {
CLIENTTERMWRITE = 1;
param->srv->so._shutdown(param->sostate, param->clisock, SHUT_WR);
}
for(after = 0, cli_events=0, srv_events=0; after < 2; after ++){
fdsc = 0;
@ -558,6 +566,9 @@ log("ready to write to client");
if(fds[fdsc].events & POLLOUT) CLIENTTERMWRITE = 1;
}
}
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL|POLLHUP)) {
CLIENTTERMREAD = 1;
CLIENTTERMWRITE = 1;
}
fdsc++;
@ -621,6 +632,9 @@ log("server terminated connection");
if(fds[fdsc].events & POLLOUT) SERVERTERMWRITE = 1;
}
}
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL|POLLHUP)) {
SERVERTERMREAD = 1;
SERVERTERMWRITE = 1;
}
fdsc++;
// }
@ -706,6 +720,24 @@ log("ready reading from server pipe");
}
}
#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(!fdsc) RETURN(90);

View File

@ -13,7 +13,6 @@
unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONNECT", (unsigned char *)"BIND", (unsigned char *)"UDPMAP"};
#define BUFSIZE 1024
#define LARGEBUFSIZE 67000
#if SOCKSTRACE > 0
char tracebuf[256];
@ -144,7 +143,7 @@ void * sockschild(struct clientparam* param) {
buf[i] = (unsigned char)res;
}
buf[i] = 0;
if(command != 1 && param->srv->family != 6 && (!strcmp((char *)buf, "0.0.0.0") || !strcmp((char *)buf, "0"))) param->req = param->srv->extsa;
if(command == 2 && param->srv->family != 6 && (!strcmp((char *)buf, "0.0.0.0") || !strcmp((char *)buf, "0"))) param->req = param->srv->extsa;
else if(!getip46(param->srv->family, buf, (struct sockaddr *) &param->req)) RETURN(100);
param->sinsr = param->req;
break;
@ -407,111 +406,7 @@ fflush(stderr);
break;
case 3:
param->sinsr = param->req;
myfree(buf);
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(&param->sincr) || memcmp(SAADDR(&sin), SAADDR(&param->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(&param->sinsr) = (size == 4)?AF_INET:AF_INET6;
memcpy(SAADDR(&param->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 *) &param->sinsr)) RETURN(100);
break;
default:
RETURN(997);
}
memcpy(SAPORT(&param->sinsr), buf+i, 2);
i+=2;
sasize = sizeof(param->sinsr);
if(len > (int)i){
socksendto(param, param->remsock, (struct sockaddr *)&param->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000);
param->statscli64+=(len - i);
param->nwrites++;
#if SOCKSTRACE > 1
myinet_ntop(*SAFAMILY(&param->sinsr), &param->sinsr, tracebuf, SASIZE(&param->sinsr));
fprintf(stderr, "UDP packet relayed from client to %s:%hu size %d, header %d\n",
tracebuf,
ntohs(*SAPORT(&param->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(&param->sinsl) == AF_INET)?1:4;
if((len = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)buf+6+SAADDRLEN(&param->sinsl), 65535 - (6+SAADDRLEN(&param->sinsl)), 0, (struct sockaddr *)&param->sinsr, &sasize)) <= 0) {
param->res = 468;
break;
}
param->statssrv64+=len;
param->nreads++;
memcpy(buf+4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
memcpy(buf+4+SAADDRLEN(&param->sinsr), SAPORT(&param->sinsr), 2);
sasize = sizeof(sin);
socksendto(param, param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(&param->sinsr), conf.timeouts[SINGLEBYTE_L]*1000);
#if SOCKSTRACE > 1
fprintf(stderr, "UDP packet relayed to client from %hu size %d\n",
ntohs(*SAPORT(&param->sinsr)),
len
);
fflush(stderr);
#endif
}
}
param->res = udpsockmap(param, conf.timeouts[CONNECTION_L]);
break;
default:
param->res = 417;

View File

@ -651,6 +651,8 @@ struct clientparam {
struct bandlim *bandlims[MAXBANDLIMS],
*bandlimsout[MAXBANDLIMS];
PROXYSOCKADDRTYPE udp_relay[3];
int udp_nhops;
time_t time_start;
};

View File

@ -53,14 +53,15 @@ void * udppmchild(struct clientparam* param) {
authres = (*param->srv->authfunc)(param);
if(authres) { RETURN(authres); }
if(!param->srv->singlepacket)hashadd(&udp_table, param, &param, MAX_COUNTER_TIME);
socksendto(param, param->remsock, (struct sockaddr *)&param->sinsr, param->srvbuf, param->srvinbuf, 0);
param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, param->srvinbuf, 0, (struct sockaddr *)&param->sinsr, SASIZE(&param->sinsr));
_3proxy_sem_unlock(udpinit);
param->statscli64 += param->srvinbuf;
param->srvinbuf = 0;
param->nwrites++;
param->clisock = param->srv->srvsock;
param->udp_nhops = 1;
param->waitserver64 = 0x7fffffffffffffff;
param->res = mapsocket(param, conf.timeouts[STRING_L]);
param->res = udpsockmap(param, conf.timeouts[STRING_L]);
_3proxy_sem_lock(udpinit);
if(!param->srv->singlepacket)hashdelete(&udp_table, param);

224
src/udpsockmap.c Normal file
View File

@ -0,0 +1,224 @@
/*
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 (serverclient 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(&param->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(&param->sincr) ||
memcmp(SAADDR(&sin), SAADDR(&param->sincr), SAADDRLEN(&sin)))
continue;
if (firstpacket) {
param->sincr = sin;
firstpacket = 0;
} else if (memcmp(SAPORT(&sin), SAPORT(&param->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(&param->sinsr) = AF_INET;
memcpy(SAADDR(&param->sinsr), param->srvbuf + 4, 4);
i = 8;
break;
case 4:
if (len < 22) return 466;
*SAFAMILY(&param->sinsr) = AF_INET6;
memcpy(SAADDR(&param->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 *)&param->sinsr))
return 100;
break;
}
default: return 997;
}
memcpy(SAPORT(&param->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 *)&param->sinsr, SASIZE(&param->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, &param->udp_relay[k]);
param->srv->so._sendto(param->sostate, param->remsock,
(char *)param->srvbuf, off + len, 0,
(struct sockaddr *)&param->udp_relay[0], SASIZE(&param->udp_relay[0]));
param->statscli64 += len;
param->nwrites++;
}
}
/* datagram from server / parent relay */
if (fds[0].revents) {
int hdrsize = (nhops == 0) ? 4 + (int)SAADDRLEN(&param->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 (nhops >= 1) {
if (!SAISNULL(&param->sinsr) && *SAPORT(&param->sinsr)) {
if (SAADDRLEN(&from) != SAADDRLEN(&param->sinsr) ||
memcmp(SAADDR(&from), SAADDR(&param->sinsr), SAADDRLEN(&from)) ||
memcmp(SAPORT(&from), SAPORT(&param->sinsr), 2))
continue;
}
} else {
if (!SAISNULL(&param->req) && *SAPORT(&param->req)) {
if (SAADDRLEN(&from) != SAADDRLEN(&param->req) ||
memcmp(SAADDR(&from), SAADDR(&param->req), SAADDRLEN(&from)) ||
memcmp(SAPORT(&from), SAPORT(&param->req), 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(&param->sinsr) == AF_INET) ? 1 : 4;
memcpy(param->srvbuf + 4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
memcpy(param->srvbuf + 4 + SAADDRLEN(&param->sinsr), SAPORT(&param->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;
}