From 983df6f7aeb6a7fe9b6481df6f06850c590a5a3e Mon Sep 17 00:00:00 2001 From: Jan Smutny Date: Fri, 25 Oct 2024 21:36:21 +0200 Subject: [PATCH] Extend SOCKS for AnyIP utilization Introduce '-k' parameter that overwrites the -e parameter (if given) and uses the IP for the external connection that corresponds to the current client connection. The benefit arises when the parameter '-i0.0.0.0' or '-i::' in case of IPv6 is set. This allows the entire range configured as local on the system to receive connections and establish connections to the target server using the IP address to which the client connected. Note: This feature is not applicable for Windows. --- man/socks.8 | 10 ++++++++++ src/common.c | 40 ++++++++++++++++++++++++++++++++++++---- src/proxymain.c | 12 ++++++++++++ src/structures.h | 1 + 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/man/socks.8 b/man/socks.8 index 6bc127b..e8444ac 100644 --- a/man/socks.8 +++ b/man/socks.8 @@ -42,6 +42,16 @@ of IP-IP NAT (will not work for PAT) Internal address. IP address proxy accepts connections to. By default connection to any interface is accepted. It\'s usually unsafe. .TP +.B -k +External address given by +.B -e +is ignored and the internal address or generally the address client conected to is used instead. +This allows to utilize AnyIP Linux feature when +.B -i0.0.0.0 +or in case of IPv6 +.B -i:: +is set. Not available for Windows platform. +.TP .B -p Port. Port proxy listens for incoming connections. Default is 1080. .TP diff --git a/src/common.c b/src/common.c index ec25eb6..402072c 100644 --- a/src/common.c +++ b/src/common.c @@ -521,16 +521,48 @@ int doconnect(struct clientparam * param){ if(!*SAPORT(¶m->sinsr))*SAPORT(¶m->sinsr) = *SAPORT(¶m->req); if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->sinsr), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {return (11);} if(SAISNULL(¶m->sinsl)){ + if (param->srv->keepip) { #ifndef NOIPV6 - if(*SAFAMILY(¶m->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6; - else + struct sockaddr_in6 local_addr; + socklen_t local_addr_len = sizeof(local_addr); + getsockname(param->clisock, (struct sockaddr *)&local_addr, &local_addr_len); + + if(*SAFAMILY(&local_addr) == AF_INET6) { + if (IN6_IS_ADDR_V4MAPPED(&local_addr.sin6_addr)) { + struct sockaddr_in6 local_addr2; + memset(&local_addr2, 0, sizeof(local_addr2)); + local_addr2.sin6_family = AF_INET; + local_addr2.sin6_port = local_addr.sin6_port; + param->sinsl = local_addr2; + } else { + param->sinsl = local_addr; + } + } else { + param->sinsl = local_addr; + } +#else + struct sockaddr_in local_addr; + socklen_t local_addr_len = sizeof(local_addr); + getsockname(new_sock, (struct sockaddr *)&local_addr, &local_addr_len); + param->sinsl = local_addr; #endif - param->sinsl = param->srv->extsa; + } else { +#ifndef NOIPV6 + if(*SAFAMILY(¶m->sinsr) == AF_INET6) param->sinsl = param->srv->extsa6; + else +#endif + param->sinsl = param->srv->extsa; + } } *SAPORT(¶m->sinsl) = 0; setopts(param->remsock, param->srv->srvsockopts); param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg)); + + if (param->srv->keepip) { + int opt = 1; + param->srv->so._setsockopt(param->sostate, param->remsock, SOL_IP, IP_FREEBIND, (char *)&opt, sizeof(int)); + } #ifdef REUSE { int opt; @@ -564,7 +596,7 @@ int doconnect(struct clientparam * param){ if(param->srv->so._bind(param->sostate, param->remsock, (struct sockaddr*)¶m->sinsl, SASIZE(¶m->sinsl))==-1) { return 12; } - + if(param->operation >= 256 || (param->operation & CONNECT)){ if(connectwithpoll(param, param->remsock,(struct sockaddr *)¶m->sinsr,SASIZE(¶m->sinsr),CONNECT_TO)) { return 13; diff --git a/src/proxymain.c b/src/proxymain.c index e0612cd..7f069d3 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -239,6 +239,9 @@ int MODULEMAINFUNC (int argc, char** argv){ "\n" " -iIP ip address or internal interface (clients are expected to connect)\n" " -eIP ip address or external interface (outgoing connection will have this)\n" +#ifndef _WIN32 + " -k outgoing connection will have local IP where client connected, thus ignores -e (useful in AnyIP case)\n" +#endif " -rHOST:PORT Use IP:port for connect back proxy instead of listen port\n" " -RHOST:PORT Use PORT to listen connect back proxy connection to pass data to\n" " -4 Use IPv4 for outgoing connections\n" @@ -377,6 +380,13 @@ int MODULEMAINFUNC (int argc, char** argv){ #endif } break; +#ifndef _WIN32 + case 'k': + { + srv.keepip = 1; + } + break; +#endif case 'N': getip46(46, (unsigned char *)argv[i]+2, (struct sockaddr *)&srv.extNat); break; @@ -763,6 +773,7 @@ int MODULEMAINFUNC (int argc, char** argv){ } else { new_sock = srv.so._accept(srv.so.state, sock, (struct sockaddr*)&defparam.sincr, &size); + if(new_sock == INVALID_SOCKET){ #ifdef _WIN32 switch(WSAGetLastError()){ @@ -938,6 +949,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){ srv->logdumpcli = conf.logdumpcli; srv->cbsock = INVALID_SOCKET; srv->needuser = 1; + srv->keepip = 0; #ifdef WITHSPLICE srv->usesplice = 1; #endif diff --git a/src/structures.h b/src/structures.h index a2f5ba7..601a9d8 100644 --- a/src/structures.h +++ b/src/structures.h @@ -479,6 +479,7 @@ struct srvparam { int paused, version; int singlepacket; int usentlm; + int keepip; int needuser; int silent; int transparent;