static int h_external(int argc, unsigned char ** argv){ int res; #ifndef NOIPV6 struct sockaddr_in6 sa6; memset(&sa6, 0, sizeof(sa6)); res = getip46(46, argv[1], (struct sockaddr *)&sa6); if(!res) return 1; if (*SAFAMILY(&sa6)==AF_INET) conf.extsa = sa6; else conf.extsa6 = sa6; #else res = getip46(46, argv[1], (struct sockaddr *)&conf.extsa); if(!res) return 1; #endif return 0; }
static int h_parent(int argc, unsigned char **argv){ struct ace *acl = NULL; struct chain *chains; acl = conf.acl; while(acl && acl->next) acl = acl->next; if(!acl || (acl->action && acl->action != 2)) { fprintf(stderr, "Chaining error: last ACL entry was not \"allow\" or \"redirect\" on line %d\n", linenum); return(1); } acl->action = 2; chains = NULL; if(!acl->chains) { chains = acl->chains = myalloc(sizeof(struct chain)); } else { chains = acl->chains; while(chains->next)chains = chains->next; chains->next = myalloc(sizeof(struct chain)); chains = chains->next; } memset(chains, 0, sizeof(struct chain)); if(!chains){ fprintf(stderr, "Chainig error: unable to allocate memory for chain\n"); return(2); } chains->weight = (unsigned)atoi((char *)argv[1]); if(chains->weight == 0 || chains->weight >1000) { fprintf(stderr, "Chaining error: bad chain weight %u line %d\n", chains->weight, linenum); return(3); } if(!strcmp((char *)argv[2], "tcp"))chains->type = R_TCP; else if(!strcmp((char *)argv[2], "http"))chains->type = R_HTTP; else if(!strcmp((char *)argv[2], "connect"))chains->type = R_CONNECT; else if(!strcmp((char *)argv[2], "socks4"))chains->type = R_SOCKS4; else if(!strcmp((char *)argv[2], "socks5"))chains->type = R_SOCKS5; else if(!strcmp((char *)argv[2], "connect+"))chains->type = R_CONNECTP; else if(!strcmp((char *)argv[2], "socks4+"))chains->type = R_SOCKS4P; else if(!strcmp((char *)argv[2], "socks5+"))chains->type = R_SOCKS5P; else if(!strcmp((char *)argv[2], "socks4b"))chains->type = R_SOCKS4B; else if(!strcmp((char *)argv[2], "socks5b"))chains->type = R_SOCKS5B; else if(!strcmp((char *)argv[2], "pop3"))chains->type = R_POP3; else if(!strcmp((char *)argv[2], "ftp"))chains->type = R_FTP; else if(!strcmp((char *)argv[2], "admin"))chains->type = R_ADMIN; else if(!strcmp((char *)argv[2], "icq"))chains->type = R_ICQ; else if(!strcmp((char *)argv[2], "extip"))chains->type = R_EXTIP; else if(!strcmp((char *)argv[2], "smtp"))chains->type = R_SMTP; else { fprintf(stderr, "Chaining error: bad chain type (%s)\n", argv[2]); return(4); } if(!getip46(46, argv[3], (struct sockaddr *)&chains->addr)) return 5; *SAPORT(&chains->addr) = htons((unsigned short)atoi((char *)argv[4])); if(argc > 5) chains->extuser = (unsigned char *)mystrdup((char *)argv[5]); if(argc > 6) chains->extpass = (unsigned char *)mystrdup((char *)argv[6]); return 0; }
int scanipl(unsigned char *arg, struct iplist *dst){ #ifndef NOIPV6 struct sockaddr_in6 sa; #else struct sockaddr_in sa; #endif char * slash, *dash; int masklen, addrlen; if((slash = strchr((char *)arg, '/'))) *slash = 0; if((dash = strchr((char *)arg,'-'))) *dash = 0; if(!getip46(46, arg, (struct sockaddr *)&sa)) return 1; memcpy(&dst->ip_from, SAADDR(&sa), SAADDRLEN(&sa)); dst->family = *SAFAMILY(&sa); if(dash){ if(!getip46(46, (unsigned char *)dash+1, (struct sockaddr *)&sa)) return 2; memcpy(&dst->ip_to, SAADDR(&sa), SAADDRLEN(&sa)); if(*SAFAMILY(&sa) != dst->family || memcmp(&dst->ip_to, &dst->ip_from, SAADDRLEN(&sa)) < 0) return 3; return 0; } memcpy(&dst->ip_to, &dst->ip_from, SAADDRLEN(&sa)); if(slash){ addrlen = SAADDRLEN(&sa); masklen = atoi(slash+1); if(masklen < 0 || masklen > (addrlen*8)) return 4; else { int i, nbytes = masklen / 8, nbits = (8 - (masklen % 8)) % 8; for(i = addrlen; i>(nbytes + (nbits > 0)); i--){ ((unsigned char *)&dst->ip_from)[i-1] = 0x00; ((unsigned char *)&dst->ip_to)[i-1] = 0xff; } for(;nbits;nbits--){ ((unsigned char *)&dst->ip_from)[nbytes] &= ~(0x01<<(nbits-1)); ((unsigned char *)&dst->ip_to)[nbytes] |= (0x01<<(nbits-1)); } return 0; } } return 0; }
static int h_nsrecord(int argc, unsigned char **argv){ #ifndef NOIPV6 struct sockaddr_in6 sa; #else struct sockaddr_in sa; #endif memset(&sa, 0, sizeof(sa)); if(!getip46(46, argv[2], (struct sockaddr *)&sa)) return 1; hashadd(*SAFAMILY(&sa)==AF_INET6?&dns6_table:&dns_table, argv[1], SAADDR(&sa), (time_t)0xffffffff); return 0; }
static int h_authnserver(int argc, unsigned char **argv){ char *str; if((str = strchr((char *)argv[1], '/'))) *str = 0; if(!getip46(46, argv[1], (struct sockaddr *)&authnserver.addr)) return 1; *SAPORT(&authnserver.addr) = htons(53); if(str) { authnserver.usetcp = strstr(str + 1, "tcp")? 1:0; *str = '/'; } return 0; }
static int h_nserver(int argc, unsigned char **argv){ char *str; if(numservers < MAXNSERVERS) { if((str = strchr((char *)argv[1], '/'))) *str = 0; if(!getip46(46, argv[1], (struct sockaddr *)&nservers[numservers].addr)) return 1; *SAPORT(&nservers[numservers].addr) = htons(53); if(str) { nservers[numservers].usetcp = strstr(str + 1, "tcp")? 1:0; *str = '/'; } numservers++; } resolvfunc = myresolver; return 0; }
static int h_internal(int argc, unsigned char ** argv){ getip46(46, argv[1], (struct sockaddr *)&conf.intsa); return 0; }
static int h_ace(int argc, unsigned char **argv){ int res = 0; int offset = 0; struct ace *acl = NULL; struct bandlim * nbl; struct trafcount * tl; if(!strcmp((char *)argv[0], "allow")){ res = ALLOW; } else if(!strcmp((char *)argv[0], "deny")){ res = DENY; } else if(!strcmp((char *)argv[0], "redirect")){ res = REDIRECT; offset = 2; } else if(!strcmp((char *)argv[0], "bandlimin")||!strcmp((char *)argv[0], "bandlimout")){ res = BANDLIM; offset = 1; } else if(!strcmp((char *)argv[0], "nobandlimin")||!strcmp((char *)argv[0], "nobandlimout")){ res = NOBANDLIM; } else if(!strcmp((char *)argv[0], "countin")){ res = COUNTIN; offset = 3; } else if(!strcmp((char *)argv[0], "nocountin")){ res = NOCOUNTIN; } else if(!strcmp((char *)argv[0], "countout")){ res = COUNTOUT; offset = 3; } else if(!strcmp((char *)argv[0], "nocountout")){ res = NOCOUNTOUT; } acl = make_ace(argc - (offset+1), argv + (offset + 1)); if(!acl) { fprintf(stderr, "Unable to parse ACL entry, line %d\n", linenum); return(1); } acl->action = res; switch(acl->action){ case REDIRECT: acl->chains = myalloc(sizeof(struct chain)); memset(acl->chains, 0, sizeof(struct chain)); if(!acl->chains) { fprintf(stderr, "No memory for ACL entry, line %d\n", linenum); return(2); } acl->chains->type = R_HTTP; if(!getip46(46, argv[1], (struct sockaddr *)&acl->chains->addr)) return 5; *SAPORT(&acl->chains->addr) = htons((unsigned short)atoi((char *)argv[2])); acl->chains->weight = 1000; acl->chains->extuser = NULL; acl->chains->extpass = NULL; acl->chains->next = NULL; case ALLOW: case DENY: if(!conf.acl){ conf.acl = acl; } else { struct ace * acei; for(acei = conf.acl; acei->next; acei = acei->next); acei->next = acl; } break; case BANDLIM: case NOBANDLIM: nbl = myalloc(sizeof(struct bandlim)); if(!nbl) { fprintf(stderr, "No memory to create band limit filter\n"); return(3); } memset(nbl, 0, sizeof(struct bandlim)); nbl->ace = acl; if(acl->action == BANDLIM) { sscanf((char *)argv[1], "%u", &nbl->rate); if(nbl->rate < 300) { fprintf(stderr, "Wrong bandwidth specified, line %d\n", linenum); return(4); } } pthread_mutex_lock(&bandlim_mutex); if(!strcmp((char *)argv[0], "bandlimin") || !strcmp((char *)argv[0], "nobandlimin")){ if(!conf.bandlimiter){ conf.bandlimiter = nbl; } else { struct bandlim * bli; for(bli = conf.bandlimiter; bli->next; bli = bli->next); bli->next = nbl; } } else { if(!conf.bandlimiterout){ conf.bandlimiterout = nbl; } else { struct bandlim * bli; for(bli = conf.bandlimiterout; bli->next; bli = bli->next); bli->next = nbl; } } pthread_mutex_unlock(&bandlim_mutex); break; case COUNTIN: case NOCOUNTIN: case COUNTOUT: case NOCOUNTOUT: tl = myalloc(sizeof(struct trafcount)); if(!tl) { fprintf(stderr, "No memory to create traffic limit filter\n"); return(5); } memset(tl, 0, sizeof(struct trafcount)); tl->ace = acl; if((acl->action == COUNTIN)||(acl->action == COUNTOUT)) { unsigned long lim; tl->comment = ( char *)argv[1]; while(isdigit(*tl->comment))tl->comment++; if(*tl->comment== '/')tl->comment++; tl->comment = mystrdup(tl->comment); sscanf((char *)argv[1], "%u", &tl->number); sscanf((char *)argv[3], "%lu", &lim); tl->type = getrotate(*argv[2]); tl->traflim64 = ((uint64_t)lim)*(1024*1024); if(!tl->traflim64) { fprintf(stderr, "Wrong traffic limit specified, line %d\n", linenum); return(6); } if(tl->number != 0 && conf.counterd >= 0) { lseek(conf.counterd, sizeof(struct counter_header) + (tl->number - 1) * sizeof(struct counter_record), SEEK_SET); memset(&crecord, 0, sizeof(struct counter_record)); read(conf.counterd, &crecord, sizeof(struct counter_record)); tl->traf64 = crecord.traf64; tl->cleared = crecord.cleared; tl->updated = crecord.updated; #ifdef _MAX__TIME64_T if(tl->cleared >= _MAX__TIME64_T || tl->updated >= _MAX__TIME64_T){ fprintf(stderr, "Invalid or corrupted counter file. Use countersutil utility to convert from older version\n"); return(6); } #endif } } pthread_mutex_lock(&tc_mutex); if(!conf.trafcounter){ conf.trafcounter = tl; } else { struct trafcount * ntl; for(ntl = conf.trafcounter; ntl->next; ntl = ntl->next); ntl->next = tl; } pthread_mutex_unlock(&tc_mutex); } return 0; }
void * sockschild(struct clientparam* param) { int res; unsigned i=0; SOCKET s; unsigned size; SASIZETYPE sasize; unsigned short port = 0; unsigned char * buf=NULL; unsigned char c; unsigned char command=0; struct pollfd fds[3]; int ver=0; int havepass = 0; #ifndef NOIPV6 struct sockaddr_in6 sin = {AF_INET6}; #else struct sockaddr_in sin = {AF_INET}; #endif int len; param->service = S_SOCKS; if(!(buf = myalloc(BUFSIZE))) {RETURN(21);} memset(buf, 0, BUFSIZE); if ((ver = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5 && ver != 4) { RETURN(401); } /* version */ param->service = ver; 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(441);} if (res == 2 && param->srv->needuser) { havepass = res; } } buf[0] = 5; buf[1] = (param->srv->needuser > 1 && !havepass)? 255 : havepass; if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);} if (param->srv->needuser > 1 && !havepass) RETURN(4); 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(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(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(481);} } if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) { RETURN(421); } /* version */ } if( (command = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) < 1 || command > 3){command = 0; RETURN(407);} /* command */ if(ver == 5){ if (sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0) == EOF) {RETURN(447);} /* reserved */ c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0); /* atype */ } else { 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(441);} buf[1] = (unsigned char) res; port = *(unsigned short*)buf; c = 1; } size = 4; *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET; switch(c) { #ifndef NOIPV6 case 4: if(param->srv->family == 4) RETURN(997); size = 16; *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6; #endif case 1: for (i = 0; i<size; i++){ if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} buf[i] = (unsigned char)res; } #ifndef NOIPV6 if (c == 1 && param->srv->family==6){ char prefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255}; *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->req) = AF_INET6; memcpy(SAADDR(¶m->sinsr), prefix, 12); memcpy(12 + (char *)SAADDR(¶m->sinsr), buf, 4); memcpy(SAADDR(¶m->req), prefix, 12); memcpy(12 + (char *)SAADDR(¶m->req), buf, 4); } else { #endif memcpy(SAADDR(¶m->sinsr), buf, size); memcpy(SAADDR(¶m->req), buf, size); #ifndef NOIPV6 } #endif if(SAISNULL(¶m->req)) { RETURN(421); } myinet_ntop(*SAFAMILY(¶m->sinsr), SAADDR(¶m->sinsr), (char *)buf, 64); break; case 3: if ((size = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} /* nmethods */ for (i=0; i<size; i++){ /* size < 256 */ if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);} buf[i] = (unsigned char)res; } buf[i] = 0; if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100); memcpy(¶m->sinsr, ¶m->req, sizeof(param->req)); break; default: RETURN(997); } if(param->hostname)myfree(param->hostname); param->hostname = (unsigned char *)mystrdup((char *)buf); if (ver == 5) { 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(441);} buf[1] = (unsigned char) res; port = *(unsigned short*)buf; } else { sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]); buf[127] = 0; if(param->srv->needuser && *buf && !param->username)param->username = (unsigned char *)mystrdup((char *)buf); if(!memcmp(SAADDR(¶m->req), "\0\0\0", 3)){ param->service = S_SOCKS45; sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]); buf[127] = 0; if(param->hostname)myfree(param->hostname); param->hostname = (unsigned char *)mystrdup((char *)buf); if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100); memcpy(¶m->sinsr, ¶m->req, sizeof(¶m->req)); } } *SAPORT(¶m->sinsr) = *SAPORT(¶m->req) = port; if(command == 1 && !*SAPORT(¶m->sinsr)) {RETURN(421);} switch(command) { case 1: param->operation = CONNECT; break; case 2: case 3: #ifndef NOIPV6 memcpy(¶m->sinsl, *SAFAMILY(¶m->req)==AF_INET6? (struct sockaddr *)¶m->srv->extsa6:(struct sockaddr *)¶m->srv->extsa, SASIZE(¶m->req)); #else memcpy(¶m->sinsl, ¶m->srv->extsa, SASIZE(¶m->req)); #endif if ((param->remsock=so._socket(SASOCK(¶m->req), command == 2? SOCK_STREAM:SOCK_DGRAM, command == 2?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);} param->operation = command == 2?BIND:UDPASSOC; break; default: RETURN(997); } if((res = (*param->srv->authfunc)(param))) { RETURN(res); } if(command > 1) { if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl))) { *SAPORT(¶m->sinsl) = 0; if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,SASIZE(¶m->sinsl)))RETURN (12); #if SOCKSTRACE > 0 fprintf(stderr, "%hu binded to communicate with server\n", *SAPORT(¶m->sins)); fflush(stderr); #endif } sasize = SASIZE(¶m->sinsl); so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &sasize); if(command == 3) { param->ctrlsock = param->clisock; param->clisock = so._socket(SASOCK(¶m->sincr), SOCK_DGRAM, IPPROTO_UDP); if(param->clisock == INVALID_SOCKET) {RETURN(11);} memcpy(&sin, ¶m->sincl, sizeof(&sin)); *SAPORT(&sin) = 0; if(so._bind(param->clisock,(struct sockaddr *)&sin,sizeof(sin))) {RETURN (12);} #if SOCKSTRACE > 0 fprintf(stderr, "%hu binded to communicate with client\n", ntohs(*SAPORT(&sin)) ); fflush(stderr); #endif } } param->res = 0; CLEANRET: if(param->clisock != INVALID_SOCKET){ int repcode; sasize = sizeof(sin); if(command != 3) so._getsockname(param->remsock, (struct sockaddr *)&sin, &sasize); else so._getsockname(param->clisock, (struct sockaddr *)&sin, &sasize); #if SOCKSTRACE > 0 fprintf(stderr, "Sending confirmation to client with code %d for %s with %s:%hu\n", param->res, commands[command], inet_ntoa(sin.sin_addr), ntohs(sin.sin_port) ); fflush(stderr); #endif if(!param->res) repcode = 0; else if(param->res <= 10) repcode = 2; else if (param->res < 20) repcode = 5; else if (param->res < 30) repcode = 1; else if (param->res < 100) repcode = 4; else repcode = param->res%10; if(ver == 5){ buf[0] = 5; buf[1] = repcode; buf[2] = 0; buf[3] = (*SAFAMILY(&sin) == AF_INET)?1:4; memcpy(buf+4, SAADDR(&sin), SAADDRLEN(&sin)); memcpy(buf+4+SAADDRLEN(&sin), SAPORT(&sin), 2); socksend((command == 3)?param->ctrlsock:param->clisock, buf, 6+SAADDRLEN(&sin), conf.timeouts[STRING_S]); } else{ buf[0] = 0; buf[1] = 90 + !!(repcode); memcpy(buf+2, SAPORT(&sin), 2); memcpy(buf+4, SAADDR(&sin), 4); socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]); } if (param->res == 0) { switch(command) { case 1: if(param->redirectfunc){ if(buf)myfree(buf); return (*param->redirectfunc)(param); } param->res = sockmap(param, conf.timeouts[CONNECTION_L]); break; case 2: so._listen (param->remsock, 1); fds[0].fd = param->remsock; fds[1].fd = param->clisock; fds[0].events = fds[1].events = POLLIN; res = so._poll(fds, 2, conf.timeouts[CONNECTION_L] * 1000); if (res < 1 || fds[1].revents) { res = 460; break; } sasize = sizeof(param->sinsr); s = so._accept(param->remsock, (struct sockaddr *)¶m->sinsr, &sasize); so._closesocket(param->remsock); param->remsock = s; if(s == INVALID_SOCKET) { param->res = 462; break; } if(SAISNULL(¶m->req) && memcmp(SAADDR(¶m->req),SAADDR(¶m->sinsr),SAADDRLEN(¶m->req))) { param->res = 470; break; } #if SOCKSTRACE > 0 fprintf(stderr, "Sending incoming connection to client with code %d for %s with %hu\n", param->res, commands[command], *SAPORT(param->sins); ); fflush(stderr); #endif if(ver == 5){ buf[3] = (*SAFAMILY(¶m->sinsr) == AF_INET)?1:4; memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr)); memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2); socksend(param->clisock, buf, 6+SAADDRLEN(¶m->sinsr), conf.timeouts[STRING_S]); } else { memcpy (buf+2, SAPORT(¶m->sinsr), 2); memcpy (buf+4, SAADDR(¶m->sinsr), 4); socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]); } param->res = sockmap(param, conf.timeouts[CONNECTION_S]); break; case 3: memcpy(¶m->sinsr, ¶m->req, sizeof(param->sinsr)); myfree(buf); if(!(buf = myalloc(LARGEBUFSIZE))) {RETURN(21);} 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 = so._poll(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 = so._recvfrom(param->clisock, buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) { param->res = 464; break; } if(SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->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; memcpy(SAADDR(¶m->sinsr), buf+4, size); *SAFAMILY(¶m->sinsr) = (size == 4)?AF_INET:AF_INET6; 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, (struct sockaddr *) ¶m->sinsr)) RETURN(100); break; default: RETURN(997); } memcpy(SAPORT(¶m->sinsr), buf+i, 2); i+=2; sasize = sizeof(param->sinsr); if(len > (int)i){ if(socksendto(param->remsock, (struct sockaddr *)¶m->sinsr, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000) <= 0){ param->res = 467; break; } param->statscli64+=(len - i); param->nwrites++; #if SOCKSTRACE > 1 fprintf(stderr, "UDP packet relayed from client to %s:%hu size %d, header %d\n", inet_ntoa(param->sins.sin_addr), ntohs(param->sins.sin_port), (len - i), i ); fprintf(stderr, "client address is assumed to be %s:%hu\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port) ); fflush(stderr); #endif } } if (fds[0].revents) { sasize = sizeof(param->sinsr); buf[0]=buf[1]=buf[2]=0; buf[3]=(*SAFAMILY(¶m->sinsl) == AF_INET)?1:4; if((len = so._recvfrom(param->remsock, buf+6+SAADDRLEN(¶m->sinsl), 65535 - 10, 0, (struct sockaddr *)¶m->sinsr, &sasize)) <= 0) { param->res = 468; break; } param->statssrv64+=len; param->nreads++; memcpy(buf+4, SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr)); memcpy(buf+4+SAADDRLEN(¶m->sinsr), SAPORT(¶m->sinsr), 2); sasize = sizeof(sin); if(socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(¶m->sinsr), conf.timeouts[SINGLEBYTE_L]*1000) <=0){ param->res = 469; break; } #if SOCKSTRACE > 1 fprintf(stderr, "UDP packet relayed to client from %hu size %d\n", ntohs(*SAPORT(¶m->sinsr)), len ); fflush(stderr); #endif } } break; default: param->res = 417; break; } }