Compare commits

...

3 Commits

Author SHA1 Message Date
Vladimir Dubrovin
4fb5c95704 Print error on non-zero local redirection in conf
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
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run
2026-08-12 17:08:09 +03:00
Vladimir Dubrovin
13a57812e5 Fix: -Ne/-Ni, -4 / -6 handling for udp mapping in socks, mixed family support in udp 2026-08-12 16:25:12 +03:00
Vladimir Dubrovin
a43c95023d Check DNS reply source in udpresolve 2026-08-12 15:32:30 +03:00
7 changed files with 108 additions and 43 deletions

View File

@ -9,6 +9,39 @@
#include "proxy.h" #include "proxy.h"
/* returns 0 on success, 1 if atyp is not supported for family, 2 if the
address is null. The address is set in both the 0 and the 2 case. */
int socks5_setaddr(int family, int atyp, const unsigned char *addr, PROXYSOCKADDRTYPE *sa){
int i, len = 4;
memset(sa, 0, sizeof(*sa));
if(atyp == 4){
#ifdef NOIPV6
return 1;
#else
if(family == 4) return 1;
len = 16;
*SAFAMILY(sa) = AF_INET6;
memcpy(SAADDR(sa), addr, 16);
#endif
}
#ifndef NOIPV6
else if(family == 6){
unsigned char prefix[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255};
*SAFAMILY(sa) = AF_INET6;
memcpy(SAADDR(sa), prefix, 12);
memcpy(12 + (unsigned char *)SAADDR(sa), addr, 4);
}
#endif
else {
*SAFAMILY(sa) = AF_INET;
memcpy(SAADDR(sa), addr, 4);
}
for(i = 0; i < len && !addr[i]; i++);
return (i == len)? 2 : 0;
}
#ifdef __linux__ #ifdef __linux__
#include <sched.h> #include <sched.h>

View File

@ -839,6 +839,24 @@ static int h_parent(int argc, unsigned char **argv){
chains->cidr = atoi(cidr + 1); chains->cidr = atoi(cidr + 1);
} }
*SAPORT(&chains->addr) = htons((uint16_t)atoi((char *)argv[4])); *SAPORT(&chains->addr) = htons((uint16_t)atoi((char *)argv[4]));
switch(chains->type){
case R_POP3:
case R_SMTP:
case R_FTP:
case R_ADMIN:
case R_TLS:
case R_DNS:
case R_HA:
if(!SAISNULL(&chains->addr) || *SAPORT(&chains->addr)){
fprintf(stderr, "Chaining error: chain type (%s) is a local redirection, it requires 0.0.0.0 as address and 0 as port on line %d\n", argv[2], linenum);
free(chains->exthost);
free(chains);
return(4);
}
break;
default:
break;
}
if(argc > 5) chains->extuser = (unsigned char *)strdup((char *)argv[5]); if(argc > 5) chains->extuser = (unsigned char *)strdup((char *)argv[5]);
if(argc > 6) chains->extpass = (unsigned char *)strdup((char *)argv[6]); if(argc > 6) chains->extpass = (unsigned char *)strdup((char *)argv[6]);
if(!acl->chains) { if(!acl->chains) {

View File

@ -205,6 +205,7 @@ extern int timeouts[12];
int sockmap(struct clientparam * param, int timeo, int usesplice); int sockmap(struct clientparam * param, int timeo, int usesplice);
int udpsockmap(struct clientparam * param, int timeo); int udpsockmap(struct clientparam * param, int timeo);
int udpbind(struct clientparam * param); int udpbind(struct clientparam * param);
int socks5_setaddr(int family, int atyp, const unsigned char *addr, PROXYSOCKADDRTYPE *sa);
#ifdef __linux__ #ifdef __linux__
int switch_ns(struct srvparam *srv, int target_fd); int switch_ns(struct srvparam *srv, int target_fd);
#endif #endif

View File

@ -505,8 +505,8 @@ int MODULEMAINFUNC (int argc, char** argv){
} }
break; break;
case 'N': case 'N':
if(argv[i][3] == 'e') getip46(46, (unsigned char *)argv[i]+3, (struct sockaddr *)&srv.extNat); if(argv[i][2] == 'e') getip46(46, (unsigned char *)argv[i]+3, (struct sockaddr *)&srv.extNat);
else if(argv[i][3] == 'i') getip46(46, (unsigned char *)argv[i]+3, (struct sockaddr *)&srv.intNat); else if(argv[i][2] == 'i') getip46(46, (unsigned char *)argv[i]+3, (struct sockaddr *)&srv.intNat);
else getip46(46, (unsigned char *)argv[i]+2, (struct sockaddr *)&srv.extNat); else getip46(46, (unsigned char *)argv[i]+2, (struct sockaddr *)&srv.extNat);
break; break;
case 'n': case 'n':

View File

@ -3,6 +3,19 @@
struct nserver nservers[MAXNSERVERS] = {{{0},0}, {{0},0}, {{0},0}, {{0},0}, {{0},0}}; struct nserver nservers[MAXNSERVERS] = {{{0},0}, {{0},0}, {{0},0}, {{0},0}, {{0},0}};
struct nserver authnserver; struct nserver authnserver;
static int dnsqmatch(const unsigned char *a, const unsigned char *b, int len){
int i;
for(i = 0; i < len; i++){
unsigned char c1 = a[i], c2 = b[i];
if(c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
if(c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
if(c1 != c2) return 1;
}
return 0;
}
uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth){ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth){
@ -23,9 +36,12 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_
SOCKET sock; SOCKET sock;
uint32_t ttl; uint32_t ttl;
PROXYSOCKADDRTYPE addr; PROXYSOCKADDRTYPE addr;
PROXYSOCKADDRTYPE from;
PROXYSOCKADDRTYPE *sinsr, *sinsl; PROXYSOCKADDRTYPE *sinsr, *sinsl;
int usetcp = 0; int usetcp = 0;
unsigned short serial = 1; unsigned short serial = 1;
unsigned char qbuf[300];
int qlen;
buf = b+2; buf = b+2;
@ -92,6 +108,9 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_
buf[len++] = (makeauth == 1)? 0x0c : (af==AF_INET6? 0x1c:0x01);/* PTR:host address */ buf[len++] = (makeauth == 1)? 0x0c : (af==AF_INET6? 0x1c:0x01);/* PTR:host address */
buf[len++] = 0; buf[len++] = 0;
buf[len++] = 1; /* INET */ buf[len++] = 1; /* INET */
qlen = len - 12;
memcpy(qbuf, buf + 12, qlen);
if(usetcp){ if(usetcp){
buf-=2; buf-=2;
*(unsigned short*)buf = htons(len); *(unsigned short*)buf = htons(len);
@ -104,30 +123,41 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_
continue; continue;
} }
if(param) param->statscli64 += len; if(param) param->statscli64 += len;
len = sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf, 4096, conf.timeouts[DNS_TO]*1000); len = sockrecvfrom(NULL, sock, (struct sockaddr *)&from, buf, 4096, conf.timeouts[DNS_TO]*1000);
if(len > 13 && usetcp){
unsigned short us;
us = ntohs(*(unsigned short*)buf);
len-=2;
buf+=2;
if(us > 4096 || us < len) len = 0;
else if(us > len){
if(sockrecvfrom(NULL, sock, (struct sockaddr *)&from, buf+len, us-len, conf.timeouts[DNS_TO]*1000) != us-len) len = 0;
else len = us;
}
}
so._shutdown(so.state, sock, SHUT_RDWR); so._shutdown(so.state, sock, SHUT_RDWR);
so._closesocket(so.state, sock); so._closesocket(so.state, sock);
if(len <= 13) { if(len <= 13) {
continue; continue;
} }
if(param) param->statssrv64 += len; if(param) param->statssrv64 += len;
if(usetcp){ if(!usetcp && (*SAFAMILY(&from) != *SAFAMILY(sinsr) ||
unsigned short us; memcmp(SAADDR(&from), SAADDR(sinsr), SAADDRLEN(sinsr)) ||
us = ntohs(*(unsigned short*)buf); *SAPORT(&from) != *SAPORT(sinsr))) {
len-=2; continue; /* not from the server we asked */
buf+=2;
if(us > 4096 || us < len || (us > len && sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf+len, us-len, conf.timeouts[DNS_TO]*1000) != us-len)) {
continue;
}
} }
if(*(unsigned short *)buf != serial)continue; if(*(unsigned short *)buf != serial)continue;
if((na = buf[7] + (((unsigned short)buf[6])<<8)) < 1) { if(!(buf[2] & 0x80)) continue; /* not a response */
return 0;
}
nq = buf[5] + (((unsigned short)buf[4])<<8); nq = buf[5] + (((unsigned short)buf[4])<<8);
if (nq != 1) { if (nq != 1) {
continue; /* we did only 1 request */ continue; /* we did only 1 request */
} }
if(len < 12 + qlen || dnsqmatch(buf + 12, qbuf, qlen)) {
continue; /* question does not match the query */
}
if((na = buf[7] + (((unsigned short)buf[6])<<8)) < 1) {
return 0;
}
for(k = 13; k<len && buf[k]; k++) { for(k = 13; k<len && buf[k]; k++) {
} }
k++; k++;

View File

@ -107,38 +107,20 @@ void * sockschild(struct clientparam* param) {
} }
size = 4; size = 4;
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET;
switch(c) { switch(c) {
#ifndef NOIPV6 #ifndef NOIPV6
case 4: case 4:
if(param->srv->family == 4) RETURN(997);
size = 16; size = 16;
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET6;
#endif #endif
case 1: case 1:
for (i = 0; i<size; i++){ for (i = 0; i<size; i++){
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
buf[i] = (unsigned char)res; buf[i] = (unsigned char)res;
} }
#ifndef NOIPV6 res = socks5_setaddr(param->srv->family, c, buf, &param->req);
if (c == 1 && param->srv->family==6){ if(res == 1) {RETURN(997);}
char prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255}; if(res == 2 && command == 1) {RETURN(431);}
*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET6; param->sinsr = param->req;
memcpy(SAADDR(&param->sinsr), prefix, 12);
memcpy(12 + (char *)SAADDR(&param->sinsr), buf, 4);
memcpy(SAADDR(&param->req), prefix, 12);
memcpy(12 + (char *)SAADDR(&param->req), buf, 4);
}
else {
#endif
memcpy(SAADDR(&param->sinsr), buf, size);
memcpy(SAADDR(&param->req), buf, size);
#ifndef NOIPV6
}
#endif
if(command == 1 && SAISNULL(&param->req)) {
RETURN(431);
}
myinet_ntop(*SAFAMILY(&param->sinsr), SAADDR(&param->sinsr), (char *)buf, 64); myinet_ntop(*SAFAMILY(&param->sinsr), SAADDR(&param->sinsr), (char *)buf, 64);
break; break;
case 3: case 3:
@ -285,7 +267,7 @@ CLEANRET:
sasize = sizeof(sin); sasize = sizeof(sin);
if(command != 3 && param->remsock != INVALID_SOCKET) param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)&sin, &sasize); if(command != 3 && param->remsock != INVALID_SOCKET) param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)&sin, &sasize);
if(!SAISNULL(&param->srv->extNat)){ if(command != 3 && !SAISNULL(&param->srv->extNat)){
uint16_t port; uint16_t port;
port = *SAPORT(&sin); port = *SAPORT(&sin);
sin = param->srv->extNat; sin = param->srv->extNat;
@ -293,7 +275,7 @@ CLEANRET:
} }
else { else {
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize); param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
if(!SAISNULL(&param->srv->intNat)){ if(command == 3 && !SAISNULL(&param->srv->intNat)){
uint16_t port; uint16_t port;
port = *SAPORT(&sin); port = *SAPORT(&sin);
sin = param->srv->intNat; sin = param->srv->intNat;

View File

@ -257,16 +257,16 @@ int udpsockmap(struct clientparam *param, int timeo)
memset(&dst, 0, sizeof(dst)); memset(&dst, 0, sizeof(dst));
switch (base[3]) { switch (base[3]) {
case 1: case 1:
*SAFAMILY(&dst) = AF_INET; if (socks5_setaddr(param->srv->family, 1, base + 4, &dst)) continue;
memcpy(SAADDR(&dst), base + 4, 4);
i = 8; i = 8;
break; break;
#ifndef NOIPV6
case 4: case 4:
if (len < 22) return 484; if (len < 22) return 484;
*SAFAMILY(&dst) = AF_INET6; if (socks5_setaddr(param->srv->family, 4, base + 4, &dst)) continue;
memcpy(SAADDR(&dst), base + 4, 16);
i = 20; i = 20;
break; break;
#endif
case 3: { case 3: {
int sz = base[4]; int sz = base[4];
if (len < 7 + sz) return 485; if (len < 7 + sz) return 485;
@ -309,7 +309,8 @@ int udpsockmap(struct clientparam *param, int timeo)
if (!nhops) param->sinsr = dst; if (!nhops) param->sinsr = dst;
if (!havedst) reconnect = 1; if (!havedst) reconnect = 1;
else if ((param->srv->udpauth & 2) && !param->dstindep) { else if (!nhops && *SAFAMILY(&dst) != *SAFAMILY(&param->sinsl)) reconnect = 1;
if (havedst && (param->srv->udpauth & 2) && !param->dstindep) {
param->preauth = 2; param->preauth = 2;
ares = (*param->srv->authfunc)(param); ares = (*param->srv->authfunc)(param);
param->preauth = 0; param->preauth = 0;