From 336b5ef35aa6c2bfa6cbd406e30c2aafc6a2f72a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Jul 2014 18:53:55 +0200 Subject: [PATCH 1/4] Try to use stdint.h with gcc <= 4.4 There's no way to tell whether the architecture has its stdint.h, as __UINT_FAST64_TYPE__ built in define didn't exist yet. Redefining the types would break the build, and chances are we're not on some exotic architecture where stdint would be missing, so let's assume it exists. --- src/pstdint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pstdint.h b/src/pstdint.h index 00fc1fc..41aa44b 100644 --- a/src/pstdint.h +++ b/src/pstdint.h @@ -191,7 +191,7 @@ * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. */ -#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED) +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 4)) )) && !defined (_PSTDINT_H_INCLUDED) #include #define _PSTDINT_H_INCLUDED # ifndef PRINTF_INT64_MODIFIER From 25a7765aed9e146ddf9ce79f8248bd2666c4dd1b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Jul 2014 18:57:57 +0200 Subject: [PATCH 2/4] Don't pad the text address with the binary form The buf gets copied to hostname and is present verbatim in logs looking like pure random garbage. Moreover you can't really strlen() it. This was likely some silly typo in inet_ntoa -> inet_ntop conversion for ipv6, since it used to be correct before. --- src/socks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socks.c b/src/socks.c index 6cdff57..1fe8a95 100644 --- a/src/socks.c +++ b/src/socks.c @@ -100,7 +100,7 @@ void * sockschild(struct clientparam* param) { if(command==1 && !param->req.sin_addr.s_addr) { RETURN(422); } - myinet_ntop(*SAFAMILY(¶m->sins), SAADDR(¶m->sins), (char *)buf + strlen((char *)buf), 64); + myinet_ntop(*SAFAMILY(¶m->sins), SAADDR(¶m->sins), (char *)buf, 64); break; case 3: if ((size = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} /* nmethods */ From 8a57314bc6365bf5cb5c12906b603b8dc4a74339 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Jul 2014 19:01:28 +0200 Subject: [PATCH 3/4] Fix some awkward NOIPV6 typoes and ommissions --- src/datatypes.c | 2 +- src/structures.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/datatypes.c b/src/datatypes.c index d5dea1d..074b62c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -69,7 +69,7 @@ static void pr_ip6(struct node *node, CBFUNC cbf, void*cb){ static void pr_sa(struct node *node, CBFUNC cbf, void*cb){ #ifdef NOIPV6 - if(node->value)return pr_ip(node, &((struct sockaddr_in *)node->value)->sin_addr.s_addr) + if(node->value)return pr_ip(node, cbf, cb); #else char buf[64]; buf[0] = '['; diff --git a/src/structures.h b/src/structures.h index 5195131..3b25c06 100644 --- a/src/structures.h +++ b/src/structures.h @@ -112,7 +112,7 @@ int #define SASIZE(sa) (((struct sockaddr_in *)sa)->sin_family == AF_INET6? sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)) #else #define SAPORT(sa) (&((struct sockaddr_in *)sa)->sin_port) -#define SAADDR(sa) ((unsigned char *)&((struct sockaddr_in *)sa)->sin_addr.a_addr) +#define SAADDR(sa) ((unsigned char *)&((struct sockaddr_in *)sa)->sin_addr.s_addr) #define SAADDRLEN(sa) (4) #define SASOCK(sa) (PF_INET) #define SASIZE(sa) (sizeof(struct sockaddr_in)) @@ -359,7 +359,7 @@ struct srvparam { #ifndef NOIPV6 struct sockaddr_in6 intsa; #else - struct sockaddr_in intsa + struct sockaddr_in intsa; #endif unsigned long extip; pthread_mutex_t counter_mutex; @@ -487,7 +487,7 @@ struct extparam { #ifndef NOIPV6 struct sockaddr_in6 intsa; #else - struct sockaddr_in intsa + struct sockaddr_in intsa; #endif unsigned long extip; unsigned short extport; From 9bdb4d56f807eea52581ccfd2a194a6aa9dbaeb0 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Jul 2014 19:08:31 +0200 Subject: [PATCH 4/4] Communicate SOCKS error states properly This used to look pretty random :( Try to keep the last decimal digits of internal errors sensible for v5 error codes. For most cases we can't really do much better than using the value of one. One specific code paths where we can return something more useful is the authentication, where we not communicate the underlying error code or signal an ACL denial. As for v4, there's not really much space to be too smart as only the code of 91 is meaningful. Therefore we limit the last digit to zero and one now. --- src/socks.c | 66 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/socks.c b/src/socks.c index 1fe8a95..592e502 100644 --- a/src/socks.c +++ b/src/socks.c @@ -48,29 +48,29 @@ void * sockschild(struct clientparam* param) { if(ver == 5){ if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} /* nmethods */ for (; i; i--) { - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(442);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} if (res == 2 && !param->srv->nouser) { havepass = res; } } buf[0] = 5; buf[1] = havepass; - if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(402);} + if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);} if (havepass) { if (((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0))) != 1) { RETURN(412); } - if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(443);} - if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(444);}; + if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} + if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);}; buf[i] = 0; if(!param->username)param->username = (unsigned char *)mystrdup((char *)buf); if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(445);} - if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(446);}; + if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);}; buf[i] = 0; if(!param->password)param->password = (unsigned char *)mystrdup((char *)buf); buf[0] = 1; buf[1] = 0; - if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(402);} + if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(481);} } if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) { RETURN(421); @@ -82,9 +82,9 @@ void * sockschild(struct clientparam* param) { c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0); /* atype */ } else { - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(448);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[0] = (unsigned char) res; - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(449);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[1] = (unsigned char) res; param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf; c = 1; @@ -93,19 +93,19 @@ void * sockschild(struct clientparam* param) { switch(c) { case 1: for (i = 0; i<4; i++){ - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(450);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[i] = (unsigned char)res; } param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = *(unsigned long *)buf; if(command==1 && !param->req.sin_addr.s_addr) { - RETURN(422); + RETURN(421); } myinet_ntop(*SAFAMILY(¶m->sins), SAADDR(¶m->sins), (char *)buf, 64); break; case 3: if ((size = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} /* nmethods */ for (i=0; ihostname)myfree(param->hostname); param->hostname = (unsigned char *)mystrdup((char *)buf); if (ver == 5) { - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(453);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[0] = (unsigned char) res; - if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(454);} + if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[1] = (unsigned char) res; param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf; } @@ -139,7 +139,7 @@ void * sockschild(struct clientparam* param) { param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip(buf); } } - if(command == 1 && !param->req.sin_port) {RETURN(424);} + if(command == 1 && !param->req.sin_port) {RETURN(421);} param->sins.sin_family = AF_INET; switch(command) { case 1: @@ -161,12 +161,38 @@ void * sockschild(struct clientparam* param) { RETURN(997); } - if((res = (*param->srv->authfunc)(param))) {RETURN(res);} + errno = 0; + if((res = (*param->srv->authfunc)(param))) { + res *= 10; + switch (errno) { + /* If authfunc failed but errno stays intacts we assume ACL denied the access, + * otherwise we do our best to pick a good error code for SOCKSv5. */ + case 0: + res += 2; /* connection not allowed by ruleset */ + break; + case ENETUNREACH: + res += 3; /* Network unreachable */ + break; + case EHOSTUNREACH: + res += 4; /* Host unreachable */ + break; + case ECONNREFUSED: + res += 5; /* Connection refused */ + break; + case EPFNOSUPPORT: + case EAFNOSUPPORT: + res += 8; /* Address type not supported */ + break; + default: + res += 1; + } + RETURN(res); + } if(command > 1) { if(so._bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins))) { param->sins.sin_port = 0; - if(so._bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins)))RETURN (12); + if(so._bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins)))RETURN (11); #if SOCKSTRACE > 0 fprintf(stderr, "%s:%hu binded to communicate with server\n", inet_ntoa(param->sins.sin_addr), @@ -183,7 +209,7 @@ fflush(stderr); if(param->clisock == INVALID_SOCKET) {RETURN(11);} memcpy(&sin, ¶m->sincl, sizeof(&sin)); *SAPORT(&sin) = htons(0); - if(so._bind(param->clisock,(struct sockaddr *)&sin,sizeof(sin))) {RETURN (12);} + if(so._bind(param->clisock,(struct sockaddr *)&sin,sizeof(sin))) {RETURN (11);} #if SOCKSTRACE > 0 fprintf(stderr, "%hu binded to communicate with client\n", ntohs(*SAPORT(&sin)) @@ -220,7 +246,7 @@ fflush(stderr); } else{ buf[0] = 0; - buf[1] = 90 + (param->res%10); + buf[1] = 90 + !!(param->res%10); memcpy(buf+2, SAPORT(&sin), 2); memcpy(buf+4, SAADDR(&sin), 4); socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]); @@ -329,7 +355,7 @@ fflush(stderr); param->sins.sin_addr.s_addr = getip(buf+4); break; default: - RETURN(996); + RETURN(997); } memcpy(¶m->sins.sin_port, buf+i, 2);