SOCKET ftpdata(struct clientparam *param){ char buf[1024]; int i; char *sb, *se; SOCKET s = INVALID_SOCKET, rem; unsigned long b1, b2, b3, b4; unsigned short b5, b6; SASIZETYPE sasize; if(socksend(param->remsock, (unsigned char *)"PASV\r\n", 6, conf.timeouts[STRING_S]) != 6){ return INVALID_SOCKET; } param->statscli64 += 6; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } if(i < 7) return INVALID_SOCKET; if(buf[0] != '2') return INVALID_SOCKET; buf[i-2] = 0; if(!(sb = strchr(buf+4, '(')) || !(se= strchr(sb, ')'))) return INVALID_SOCKET; if(sscanf(sb+1, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) return INVALID_SOCKET; sasize = sizeof(param->sinsl); if(so._getsockname(param->remsock, (struct sockaddr *)¶m->sinsl, &sasize)){return INVALID_SOCKET;} sasize = sizeof(param->sinsr); if(so._getpeername(param->remsock, (struct sockaddr *)¶m->sinsr, &sasize)){return INVALID_SOCKET;} rem = param->remsock; param->remsock = INVALID_SOCKET; param->req = param->sinsr; *SAPORT(¶m->req) = *SAPORT(¶m->sinsr) = htons((unsigned short)((b5<<8)^b6)); *SAPORT(¶m->sinsl) = 0; i = param->operation; param->operation = FTP_DATA; if((param->res = (*param->srv->authfunc)(param))) { if(param->remsock != INVALID_SOCKET) { so._closesocket(param->remsock); param->remsock = INVALID_SOCKET; } memset(¶m->sinsl, 0, sizeof(param->sinsl)); if((param->res = (*param->srv->authfunc)(param))) { param->remsock = rem; return INVALID_SOCKET; } } param->operation = i; s = param->remsock; param->remsock = rem; return s; }
int checkACL(struct clientparam * param){ struct ace* acentry; if(!param->srv->acl) { return alwaysauth(param); } for(acentry = param->srv->acl; acentry; acentry = acentry->next) { if(ACLmatches(acentry, param)) { param->nolog = acentry->nolog; param->weight = acentry->weight; if(acentry->action == 2) { struct ace dup; if(param->operation < 256 && !(param->operation & CONNECT)){ continue; } if(param->redirected && acentry->chains && SAISNULL(&acentry->chains->addr) && !*SAPORT(&acentry->chains->addr)) { continue; } dup = *acentry; return handleredirect(param, &dup); } return acentry->action; } } return 3; }
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; }
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_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; 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; #else struct sockaddr_in sin; #endif int len; param->req.sin_addr.s_addr = 0; param->service = S_SOCKS; if (!(buf = (char *)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 = (PROXYSERVICE)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->nouser) { havepass = res; } } buf[0] = 5; buf[1] = havepass; if(socksend(param->clisock, (unsigned char *)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(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, (unsigned char *)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; param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf; c = 1; } switch(c) { case 1: for (i = 0; i<4; i++){ 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(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; 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; param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip((unsigned char *)buf); if(command==1 && !param->req.sin_addr.s_addr) { RETURN(100); } 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; param->sins.sin_port = param->req.sin_port = *(unsigned short*)buf; } else { sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]); buf[127] = 0; if(!param->srv->nouser && *buf && !param->username)param->username = (unsigned char *)mystrdup((char *)buf); if(param->sins.sin_addr.s_addr && ntohl(param->sins.sin_addr.s_addr)<256){ 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); param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip((unsigned char *)buf); } } if(command == 1 && !param->req.sin_port) {RETURN(421);} param->sins.sin_family = AF_INET; switch(command) { case 1: param->operation = CONNECT; break; case 2: param->sins.sin_addr.s_addr = param->extip; param->sins.sin_port = param->extport?param->extport:param->req.sin_port; if ((param->remsock=so._socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);} param->operation = BIND; break; case 3: param->sins.sin_port = param->extport?param->extport:param->req.sin_port; param->sins.sin_addr.s_addr = param->extip; if ((param->remsock=so._socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);} param->operation = UDPASSOC; break; default: RETURN(997); } if((res = (*param->srv->authfunc)(param))) { 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 SOCKSTRACE > 0 fprintf(stderr, "%s:%hu binded to communicate with server\n", inet_ntoa(param->sins.sin_addr), ntohs(param->sins.sin_port) ); fflush(stderr); #endif } sasize = sizeof(param->sins); so._getsockname(param->remsock, (struct sockaddr *)¶m->sins, &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) = htons(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] = 1; memcpy(buf+4, SAADDR(&sin), 4); memcpy(buf+8, SAPORT(&sin), 2); socksend((command == 3) ? param->ctrlsock : param->clisock, (unsigned char *)buf, 10, 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, (unsigned char *)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[(param->req.sin_addr.s_addr)?CONNECTION_S:CONNECTION_L] * 1000); if (res < 1 || fds[1].revents) { res = 460; break; } sasize = sizeof(param->sins); s = so._accept(param->remsock, (struct sockaddr *)¶m->sins, &sasize); so._closesocket(param->remsock); param->remsock = s; if(s == INVALID_SOCKET) { param->res = 462; break; } if(param->req.sin_addr.s_addr && param->req.sin_addr.s_addr != param->sins.sin_addr.s_addr) { param->res = 470; break; } #if SOCKSTRACE > 0 fprintf(stderr, "Sending incoming connection to client with code %d for %s with %s:%hu\n", param->res, commands[command], inet_ntoa(param->sins.sin_addr), ntohs(param->sins.sin_port) ); fflush(stderr); #endif if(ver == 5){ memcpy (buf+4, ¶m->sins.sin_addr, 4); memcpy (buf+8, ¶m->sins.sin_port, 2); socksend(param->clisock, (unsigned char *)buf, 10, conf.timeouts[STRING_S]); } else { memcpy (buf+2, ¶m->sins.sin_port, 2); memcpy (buf+4, ¶m->sins.sin_addr, 4); socksend(param->clisock, (unsigned char *)buf, 8, conf.timeouts[STRING_S]); } param->res = sockmap(param, conf.timeouts[CONNECTION_S]); break; case 3: param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr; param->sins.sin_port = param->req.sin_port; myfree(buf); if (!(buf = (char *)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; } switch(buf[3]) { case 1: i = 8; memcpy(¶m->sins.sin_addr.s_addr, buf+4, 4); break; case 3: size = buf[4]; for (i=4; size; i++, size--){ buf[i] = buf[i+1]; } buf[i++] = 0; param->sins.sin_addr.s_addr = getip((unsigned char *)buf + 4); break; default: RETURN(997); } memcpy(¶m->sins.sin_port, buf+i, 2); i+=2; sasize = sizeof(param->sins); if(len > (int)i){ if (socksendto(param->remsock, (struct sockaddr *)¶m->sins, (unsigned char *)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) { struct sockaddr_in tsin; sasize = sizeof(tsin); buf[0]=buf[1]=buf[2]=0; buf[3]=1; if((len = so._recvfrom(param->remsock, buf+10, 65535 - 10, 0, (struct sockaddr *)&tsin, &sasize)) <= 0) { param->res = 468; break; } param->statssrv64+=len; param->nreads++; memcpy(buf+4, &tsin.sin_addr.s_addr, 4); memcpy(buf+8, &tsin.sin_port, 2); sasize = sizeof(param->sins); if (socksendto(param->clisock, (struct sockaddr *)&sin, (unsigned char *)buf, len + 10, conf.timeouts[SINGLEBYTE_L] * 1000) <= 0){ param->res = 469; break; } #if SOCKSTRACE > 1 fprintf(stderr, "UDP packet relayed to client from %s:%hu size %d\n", inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port), len ); fflush(stderr); #endif } } break; default: param->res = 417; break; } } } if(command > 3) command = 0; if(buf){ sprintf((char *)buf, "%s ", commands[command]); if(param->hostname){ sprintf((char *)buf + strlen((char *)buf), "%.265s", param->hostname); } else myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + strlen((char *)buf), 64); sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(param->req.sin_port)); (*param->srv->logfunc)(param, (unsigned char *)buf); myfree(buf); } freeparam(param); return (NULL); }
int ACLmatches(struct ace* acentry, struct clientparam * param){ struct userlist * userentry; struct iplist *ipentry; struct portlist *portentry; struct period *periodentry; unsigned char * username; struct hostname * hstentry=NULL; int i; int match = 0; username = param->username?param->username:(unsigned char *)"-"; if(acentry->src) { for(ipentry = acentry->src; ipentry; ipentry = ipentry->next) if(IPInentry((struct sockaddr *)¶m->sincr, ipentry)) { break; } if(!ipentry) return 0; } if((acentry->dst && !SAISNULL(¶m->req)) || (acentry->dstnames && param->hostname)) { for(ipentry = acentry->dst; ipentry; ipentry = ipentry->next) if(IPInentry((struct sockaddr *)¶m->req, ipentry)) { break; } if(!ipentry) { if(acentry->dstnames && param->hostname){ for(i=0; param->hostname[i]; i++){ param->hostname[i] = tolower(param->hostname[i]); } while(i > 5 && param->hostname[i-1] == '.') param->hostname[i-1] = 0; for(hstentry = acentry->dstnames; hstentry; hstentry = hstentry->next){ switch(hstentry->matchtype){ case 0: if(strstr((char *)param->hostname, (char *)hstentry->name)) match = 1; break; case 1: if(strstr((char *)param->hostname, (char *)hstentry->name) == (char *)param->hostname) match = 1; break; case 2: if(strstr((char *)param->hostname, (char *)hstentry->name) == (char *)(param->hostname + i - (strlen((char *)hstentry->name)))) match = 1; break; default: if(!strcmp((char *)param->hostname, (char *)hstentry->name)) match = 1; break; } if(match) break; } } } if(!ipentry && !hstentry) return 0; } if(acentry->ports && *SAPORT(¶m->req)) { for (portentry = acentry->ports; portentry; portentry = portentry->next) if(ntohs(*SAPORT(¶m->req)) >= portentry->startport && ntohs(*SAPORT(¶m->req)) <= portentry->endport) { break; } if(!portentry) return 0; } if(acentry->wdays){ if(!(acentry -> wdays & wday)) return 0; } if(acentry->periods){ int start_time = (int)(param->time_start - basetime); for(periodentry = acentry->periods; periodentry; periodentry = periodentry -> next) if(start_time >= periodentry->fromtime && start_time < periodentry->totime){ break; } if(!periodentry) return 0; } if(acentry->users){ for(userentry = acentry->users; userentry; userentry = userentry->next) if(!strcmp((char *)username, (char *)userentry->user)){ break; } if(!userentry) return 0; } if(acentry->operation) { if((acentry->operation & param->operation) != param->operation){ return 0; } } if(acentry->weight && (acentry->weight < param->weight)) return 0; return 1; }
int handleredirect(struct clientparam * param, struct ace * acentry){ int connected = 0; int weight = 1000; int res; int done = 0; struct chain * cur; struct chain * redir = NULL; int r2; if(param->remsock != INVALID_SOCKET) { return 0; } if(SAISNULL(¶m->req) || !*SAPORT(¶m->req)) { return 100; } r2 = (myrand(param, sizeof(struct clientparam))%1000); for(cur = acentry->chains; cur; cur=cur->next){ if(((weight = weight - cur->weight) > r2)|| done) { if(weight <= 0) { weight += 1000; done = 0; r2 = (myrand(param, sizeof(struct clientparam))%1000); } continue; } param->redirected++; done = 1; if(weight <= 0) { weight += 1000; done = 0; r2 = (myrand(param, sizeof(struct clientparam))%1000); } if(!connected){ if(cur->type == R_EXTIP){ param->sinsl = cur->addr; if(cur->next)continue; return 0; } else if(SAISNULL(&cur->addr) && !*SAPORT(&cur->addr)){ if(cur->extuser){ if(param->extusername) myfree(param->extusername); param->extusername = (unsigned char *)mystrdup((char *)((*cur->extuser == '*' && param->username)? param->username : cur->extuser)); if(cur->extpass){ if(param->extpassword) myfree(param->extpassword); param->extpassword = (unsigned char *)mystrdup((char *)((*cur->extuser == '*' && param->password)?param->password : cur->extpass)); } if(*cur->extuser == '*' && !param->username) return 4; } switch(cur->type){ case R_POP3: param->redirectfunc = pop3pchild; break; case R_FTP: param->redirectfunc = ftpprchild; break; case R_ADMIN: param->redirectfunc = adminchild; break; case R_ICQ: param->redirectfunc = icqprchild; break; case R_SMTP: param->redirectfunc = smtppchild; break; default: param->redirectfunc = proxychild; } if(cur->next)continue; return 0; } else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) { unsigned short port = *SAPORT(¶m->sinsr); param->sinsr = cur->addr; *SAPORT(¶m->sinsr) = port; } else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(¶m->sinsr) = *SAPORT(&cur->addr); else { param->sinsr = cur->addr; } if((res = alwaysauth(param))){ return (res == 10)? res : 60+res; } } else { res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&cur->addr):0; if(res) return res; } redir = cur; param->redirtype = redir->type; if(redir->type == R_TCP || redir->type ==R_HTTP) { if(cur->extuser){ if(*cur -> extuser == '*' && !param->username) return 4; if(param->extusername) myfree(param->extusername); param->extusername = (unsigned char *)mystrdup((char *)((*cur->extuser == '*' && param->username)? param->username : cur->extuser)); if(cur->extpass){ if(param->extpassword) myfree(param->extpassword); param->extpassword = (unsigned char *)mystrdup((char *)((*cur->extuser == '*' && param->password)?param->password : cur->extpass)); } } return 0; } connected = 1; } if(!connected) return 9; return (redir)?clientnegotiate(redir, param, (struct sockaddr *)¶m->req):0; }
int clientnegotiate(struct chain * redir, struct clientparam * param, struct sockaddr * addr){ unsigned char *buf; unsigned char *username; int res; int len=0; unsigned char * user, *pass; user = redir->extuser; pass = redir->extpass; if (param->srvinbuf < 4096){ if(param->srvbuf)myfree(param->srvbuf); param->srvbuf = myalloc(4096); param->srvbufsize = 4096; } buf = param->srvbuf; username = buf + 2048; if(user) { if (*user == '*') { if(!param->username) return 4; user = param->username; pass = param->password; } } switch(redir->type){ case R_TCP: case R_HTTP: return 0; case R_CONNECT: case R_CONNECTP: { len = sprintf((char *)buf, "CONNECT "); if(redir->type == R_CONNECTP && param->hostname) { char * needreplace; needreplace = strchr((char *)param->hostname, ':'); if(needreplace) buf[len++] = '['; len += sprintf((char *)buf + len, "%.256s", (char *)param->hostname); if(needreplace) buf[len++] = ']'; } else { if(*SAFAMILY(addr) == AF_INET6) buf[len++] = '['; len += myinet_ntop(*SAFAMILY(addr), SAADDR(addr), (char *)buf+len, 256); if(*SAFAMILY(addr) == AF_INET6) buf[len++] = ']'; } len += sprintf((char *)buf + len, ":%hu HTTP/1.0\r\nProxy-Connection: keep-alive\r\n", ntohs(*SAPORT(addr))); if(user){ len += sprintf((char *)buf + len, "Proxy-authorization: basic "); sprintf((char *)username, "%.128s:%.64s", user, pass?pass:(unsigned char *)""); en64(username, buf+len, (int)strlen((char *)username)); len = (int)strlen((char *)buf); len += sprintf((char *)buf + len, "\r\n"); } len += sprintf((char *)buf + len, "\r\n"); if(socksend(param->remsock, buf, len, conf.timeouts[CHAIN_TO]) != (int)strlen((char *)buf)) return 31; param->statssrv64+=len; param->nwrites++; if((res = sockgetlinebuf(param, SERVER,buf,13,'\n',conf.timeouts[CHAIN_TO])) < 13) return 32; if(buf[9] != '2') return 33; while((res = sockgetlinebuf(param, SERVER,buf,1023,'\n', conf.timeouts[CHAIN_TO])) > 2); if(res <= 0) return 34; return 0; } case R_SOCKS4: case R_SOCKS4P: case R_SOCKS4B: { if(*SAFAMILY(addr) != AF_INET) return 44; buf[0] = 4; buf[1] = 1; memcpy(buf+2, SAPORT(addr), 2); if(redir->type == R_SOCKS4P && param->hostname) { buf[4] = buf[5] = buf[6] = 0; buf[7] = 3; } else memcpy(buf+4, SAADDR(addr), 4); if(!user)user = (unsigned char *)"anonymous"; len = (int)strlen((char *)user) + 1; memcpy(buf+8, user, len); len += 8; if(redir->type == R_SOCKS4P && param->hostname) { int hostnamelen; hostnamelen = (int)strlen((char *)param->hostname) + 1; if(hostnamelen > 255) hostnamelen = 255; memcpy(buf+len, param->hostname, hostnamelen); len += hostnamelen; } if(socksend(param->remsock, buf, len, conf.timeouts[CHAIN_TO]) < len){ return 41; } param->statssrv64+=len; param->nwrites++; if((len = sockgetlinebuf(param, SERVER, buf, (redir->type == R_SOCKS4B)? 3:8, EOF, conf.timeouts[CHAIN_TO])) != ((redir->type == R_SOCKS4B)? 3:8)){ return 42; } if(buf[1] != 90) { return 43; } } return 0; case R_SOCKS5: case R_SOCKS5P: case R_SOCKS5B: { int inbuf = 0; buf[0] = 5; buf[1] = 1; buf[2] = user? 2 : 0; if(socksend(param->remsock, buf, 3, conf.timeouts[CHAIN_TO]) != 3){ return 51; } param->statssrv64+=len; param->nwrites++; if(sockgetlinebuf(param, SERVER, buf, 2, EOF, conf.timeouts[CHAIN_TO]) != 2){ return 52; } if(buf[0] != 5) { return 53; } if(buf[1] != 0 && !(buf[1] == 2 && user)){ return 54; } if(buf[1] == 2){ buf[inbuf++] = 1; buf[inbuf] = (unsigned char)strlen((char *)user); memcpy(buf+inbuf+1, user, buf[inbuf]); inbuf += buf[inbuf] + 1; buf[inbuf] = pass?(unsigned char)strlen((char *)pass):0; if(pass)memcpy(buf+inbuf+1, pass, buf[inbuf]); inbuf += buf[inbuf] + 1; if(socksend(param->remsock, buf, inbuf, conf.timeouts[CHAIN_TO]) != inbuf){ return 51; } param->statssrv64+=inbuf; param->nwrites++; if(sockgetlinebuf(param, SERVER, buf, 2, EOF, 60) != 2){ return 55; } if(buf[0] != 1 || buf[1] != 0) { return 56; } } buf[0] = 5; buf[1] = 1; buf[2] = 0; if(redir->type == R_SOCKS5P && param->hostname) { buf[3] = 3; len = (int)strlen((char *)param->hostname); if(len > 255) len = 255; buf[4] = len; memcpy(buf + 5, param->hostname, len); len += 5; } else { len = 3; buf[len++] = (*SAFAMILY(addr) == AF_INET)? 1 : 4; memcpy(buf+len, SAADDR(addr), SAADDRLEN(addr)); len += SAADDRLEN(addr); } memcpy(buf+len, SAPORT(addr), 2); len += 2; if(socksend(param->remsock, buf, len, conf.timeouts[CHAIN_TO]) != len){ return 51; } param->statssrv64+=len; param->nwrites++; if(sockgetlinebuf(param, SERVER, buf, 4, EOF, conf.timeouts[CHAIN_TO]) != 4){ return 57; } if(buf[0] != 5) { return 53; } if(buf[1] != 0) { return 60 + (buf[1] % 10); } if(buf[3] != 1) { return 58; } if (redir->type != R_SOCKS5B && sockgetlinebuf(param, SERVER, buf, 6, EOF, conf.timeouts[CHAIN_TO]) != 6){ return 59; } return 0; } default: return 30; } }
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; } }