diff --git a/src/auth.c b/src/auth.c index 33bef3b..6cd64e5 100644 --- a/src/auth.c +++ b/src/auth.c @@ -148,7 +148,13 @@ int doauth(struct clientparam * param){ if(ret > 9) return ret; } if(!res){ - ret = alwaysauth(param); + /* UDP parent negotiation already established its control connection. */ + if(param->operation == UDPASSOC && param->ctrlsocksrv != INVALID_SOCKET) { + ret = 0; + } + else { + ret = alwaysauth(param); + } if (param->afterauthfilters){ FILTER_ACTION action; diff --git a/src/socks.c b/src/socks.c index 1874745..804e245 100644 --- a/src/socks.c +++ b/src/socks.c @@ -436,7 +436,8 @@ fflush(stderr); param->res = mapsocket(param, conf.timeouts[CONNECTION_S]); break; case 3: - param->sinsr = param->req; + if(param->udp_nhops) param->sinsr = param->udp_relay[0]; + else param->sinsr = param->req; param->res = udpsockmap(param, conf.timeouts[CONNECTION_L]); break; default: diff --git a/src/udpsockmap.c b/src/udpsockmap.c index af2c39f..5813acc 100644 --- a/src/udpsockmap.c +++ b/src/udpsockmap.c @@ -35,6 +35,42 @@ static int socks5_udp_skip_hdr(unsigned char *buf, int len) return (off <= len) ? off : -1; } +static int socks5_udp_parse_dst(struct clientparam *param, const unsigned char *buf, + int len, PROXYSOCKADDRTYPE *dst) +{ + int hostlen; + char hostname[256]; + + if (len < 4 || buf[0] || buf[1] || buf[2]) return 483; + memset(dst, 0, sizeof(*dst)); + switch (buf[3]) { + case 1: + if (len < 10) return 483; + *SAFAMILY(dst) = AF_INET; + memcpy(SAADDR(dst), buf + 4, 4); + memcpy(SAPORT(dst), buf + 8, 2); + return 0; + case 4: + if (len < 22) return 484; + *SAFAMILY(dst) = AF_INET6; + memcpy(SAADDR(dst), buf + 4, 16); + memcpy(SAPORT(dst), buf + 20, 2); + return 0; + case 3: + if (len < 5) return 485; + hostlen = buf[4]; + if (len < 7 + hostlen) return 485; + memcpy(hostname, buf + 5, hostlen); + hostname[hostlen] = 0; + if (!getip46(param->srv->family, (unsigned char *)hostname, + (struct sockaddr *)dst)) return 100; + memcpy(SAPORT(dst), buf + 5 + hostlen, 2); + return 0; + default: + return 997; + } +} + /* * udpsockmap: bidirectional UDP relay. * @@ -156,6 +192,7 @@ int udpsockmap(struct clientparam *param, int timeo) default: return 997; } memcpy(SAPORT(¶m->sinsr), param->srvbuf + i, 2); + param->req = param->sinsr; i += 2; if (len > i) { param->srv->so._sendto(param->sostate, param->remsock, @@ -166,6 +203,13 @@ int udpsockmap(struct clientparam *param, int timeo) } } else { int off = 0; + int dstres; + + if (param->srv->service == S_SOCKS) { + dstres = socks5_udp_parse_dst(param, param->srvbuf + recvoff, + len, ¶m->req); + if (dstres) return dstres; + } 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,