void * pop3pchild(void * data) { #define param ((struct clientparam*)data) int i=0, res; unsigned char buf[320]; unsigned char *se; if(socksend(param->clisock, (unsigned char *)"+OK Proxy\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (611);} i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); while(i > 4 && strncasecmp((char *)buf, "USER", 4)){ if(!strncasecmp((char *)buf, "QUIT", 4)){ socksend(param->clisock, (unsigned char *)"+OK\r\n", 5,conf.timeouts[STRING_S]); RETURN(0); } socksend(param->clisock, (unsigned char *)"-ERR need USER first\r\n", 22, conf.timeouts[STRING_S]); i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]); } if(i<6) {RETURN(612);} buf[i] = 0; if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0; if (strncasecmp((char *)buf, "USER ", 5)){RETURN (614);} if(!param->hostname && param->remsock == INVALID_SOCKET) { if(parseconnusername((char *)buf +5, param, 0, 110)){RETURN(615);} } else if(parseusername((char *)buf + 5, param, 0)) {RETURN(616);} param->operation = CONNECT; res = (*param->authfunc)(param); if(res) {RETURN(res);} i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]); param->statssrv+=i; if( i < 3 ) {RETURN(621);} buf[i] = 0; if(strncasecmp((char *)buf, "+OK", 3)||!strncasecmp((char *)buf+4, "PROXY", 5)){RETURN(622);} if( socksend(param->remsock, (unsigned char *)"USER ", 5, conf.timeouts[STRING_S])!= 5 || socksend(param->remsock, param->extusername, strlen((char *)param->extusername), conf.timeouts[STRING_S]) <= 0 || socksend(param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S])!=2) {RETURN(623);} param->statscli += (strlen((char *)param->extusername) + 7); RETURN (sockmap(param, 180)); CLEANRET: if(param->hostname&¶m->extusername) { sprintf((char *)buf, "%.64s@%.128s%c%hu", param->extusername, param->hostname, (ntohs(param->sins.sin_port)==110)?0:':', ntohs(param->sins.sin_port)); (*param->logfunc)(param, buf); } else (*param->logfunc)(param, NULL); if(param->clisock != INVALID_SOCKET) { if ((param->res > 0 && param->res < 100) || (param->res > 611 && param->res <700)) socksend(param->clisock, (unsigned char *)"-ERR\r\n", 6,conf.timeouts[STRING_S]); } freeparam(param); return (NULL); }
SOCKET ftpcommand(struct clientparam *param, unsigned char * command, unsigned char *arg) { char buf[1024]; int i; SOCKET s; s = ftpdata(param); if(s==INVALID_SOCKET) return INVALID_SOCKET; sprintf(buf, "%.15s%s%.512s\r\n", command, arg? (unsigned char *)" ":(unsigned char *)"", arg?arg:(unsigned char *)""); if((int)socksend(param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){ so._closesocket(s); return INVALID_SOCKET; } param->statscli64 += (int)strlen(buf); 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 < 3) { so._closesocket(s); return INVALID_SOCKET; } if(buf[0] != '1') { so._closesocket(s); return INVALID_SOCKET; } return s; }
int ftpres(struct clientparam *param, unsigned char * buf, int l){ int i; if (l < 16) return 755; while((i = sockgetlinebuf(param, SERVER, buf, l - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } buf[i] = 0; if(i < 3) return 751; if(buf[0] != '2' && buf[0] != '1') return 750; return 0; }
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 ftptype(struct clientparam *param, unsigned char* f_type){ char buf[1024]; int i; sprintf(buf, "TYPE %.512s\r\n", f_type); if((int)socksend(param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){ return 741; } param->statscli64 += (int)strlen(buf); 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 < 3) return 742; if(buf[0] != '2') return 740; return 0; }
int ftpsyst(struct clientparam *param, unsigned char *buf, unsigned len){ int i; if(socksend(param->remsock, (unsigned char *)"SYST\r\n", 6, conf.timeouts[STRING_S]) != 6){ return 721; } param->statscli64 += 6; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } if(i < 7) return 722; buf[3] = 0; if(atoi((char *)buf)/100 != 2) return 723; buf[i-2] = 0; strcpy((char *)buf, (char *)buf+4); return 0; }
int ftpcd(struct clientparam *param, unsigned char* path, char *nbuf, int *innbuf){ char buf[1024]; int i; int inbuf = 0; sprintf(buf, "CWD %.512s\r\n", path); if((int)socksend(param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){ return 711; } param->statscli64 += (int)strlen(buf); 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(nbuf && innbuf && inbuf + i < *innbuf && i > 6) { memcpy(nbuf + inbuf, buf, i); inbuf += i; } } if(innbuf)*innbuf = inbuf; if(i < 3) return 712; buf[3] = 0; if(buf[0] != '2') return 710; return 0; }
int ftppwd(struct clientparam *param, unsigned char *buf, unsigned len){ int i; char *b, *e; if(socksend(param->remsock, (unsigned char *)"PWD\r\n", 5, conf.timeouts[STRING_S]) != 5){ return 731; } param->statscli64 += 5; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } if(i < 7) return 732; buf[3] = 0; if(atoi((char *)buf)/100 != 2) return 733; buf[i-2] = 0; b = (char *)buf+4; if(*b == '\"' && (e = strchr(b+1, '\"'))){ b++; *e = 0; } strcpy((char *)buf, b); return 0; }
void * sockschild(struct clientparam* param) { int res; unsigned i=0; SOCKET s; unsigned size; SASIZETYPE sasize; unsigned char * buf=NULL; unsigned char c; unsigned char command=0; struct pollfd fds[3]; int ver=0; int havepass = 0; struct sockaddr_in sin; int len; param->req.sin_addr.s_addr = 0; 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(442);} 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 (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);}; 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);}; 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 ((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(448);} buf[0] = (unsigned char) res; if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(449);} 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(450);} 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); } myinet_ntoa(param->sins.sin_addr, (char *)buf); 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(452);} buf[i] = (unsigned char)res; } buf[i] = 0; param->sins.sin_addr.s_addr = param->req.sin_addr.s_addr = getip(buf); if(command==1 && !param->req.sin_addr.s_addr) { RETURN(100); } break; default: RETURN(998); } 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(453);} buf[0] = (unsigned char) res; if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(454);} 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(buf); } } if(command == 1 && !param->req.sin_port) {RETURN(424);} 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=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=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(bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(param->sins))) { param->sins.sin_port = 0; if(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(struct sockaddr_in); getsockname(param->remsock, (struct sockaddr *)¶m->sins, &sasize); if(command == 3) { param->ctrlsock = param->clisock; param->clisock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(param->clisock == INVALID_SOCKET) {RETURN(11);} sin.sin_family = AF_INET; sin.sin_addr.s_addr = param->srv->intip; sin.sin_port = htons(0); if(bind(param->clisock,(struct sockaddr *)&sin,sizeof(struct sockaddr_in))) {RETURN (12);} #if SOCKSTRACE > 0 fprintf(stderr, "%s:%hu binded to communicate with client\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port) ); fflush(stderr); #endif } } param->res = 0; CLEANRET: if(param->clisock != INVALID_SOCKET){ sasize = sizeof(struct sockaddr_in); if(command != 3) getsockname(param->remsock, (struct sockaddr *)&sin, &sasize); else 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(ver == 5){ buf[0] = 5; buf[1] = param->res%10; buf[2] = 0; buf[3] = 1; memcpy(buf+4, &sin.sin_addr.s_addr, 4); memcpy(buf+8, &sin.sin_port, 2); socksend((command == 3)?param->ctrlsock:param->clisock, buf, 10, conf.timeouts[STRING_S]); } else{ buf[0] = 0; buf[1] = 90 + (param->res%10); memcpy(buf+2, &sin.sin_port, 2); memcpy(buf+4, &sin.sin_addr.s_addr, 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: listen (param->remsock, 1); fds[0].fd = param->remsock; fds[1].fd = param->clisock; fds[0].events = fds[1].events = POLLIN; res = 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 = accept(param->remsock, (struct sockaddr *)¶m->sins, &sasize); 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, 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, 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 = 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 = 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(struct sockaddr_in); if((len = recvfrom(param->clisock, buf, 65535, 0, (struct sockaddr *)&sin, &sasize)) <= 10) { param->res = 464; break; } if(sin.sin_addr.s_addr != param->sinc.sin_addr.s_addr){ 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(buf+4); break; default: RETURN(996); } memcpy(¶m->sins.sin_port, buf+i, 2); i+=2; sasize = sizeof(param->sins); if(len > (int)i){ if(socksendto(param->remsock, ¶m->sins, buf+i, len - i, conf.timeouts[SINGLEBYTE_L]*1000) <= 0){ param->res = 467; break; } param->statscli+=(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 = recvfrom(param->remsock, buf+10, 65535 - 10, 0, (struct sockaddr *)&tsin, &sasize)) <= 0) { param->res = 468; break; } param->statssrv+=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, &sin, 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_ntoa(param->req.sin_addr, (char *)buf+strlen((char *)buf)); sprintf((char *)buf+strlen((char *)buf), ":%hu", ntohs(param->req.sin_port)); (*param->srv->logfunc)(param, buf); myfree(buf); } freeparam(param); return (NULL); }
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 * ftpprchild(struct clientparam* param) { int i=0, res; unsigned char *buf; unsigned char *se; int status = 0; int inbuf; int pasv = 0; SOCKET sc = INVALID_SOCKET, ss = INVALID_SOCKET, clidatasock = INVALID_SOCKET; SASIZETYPE sasize; char * req = NULL; struct linger lg; struct pollfd fds; if(!(buf = myalloc(BUFSIZE))) RETURN(876); param->ctrlsock = param->clisock; param->operation = CONNECT; lg.l_onoff = 1; lg.l_linger = conf.timeouts[STRING_L];; if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);} for(;;){ i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 10, '\n', conf.timeouts[CONNECTION_S]); if(!i) { RETURN(0); } if(i<4) {RETURN(802);} buf[i] = 0; if ((se=(unsigned char *)strchr((char *)buf, '\r'))) *se = 0; if (req) myfree (req); req = NULL; if (!strncasecmp((char *)buf, "OPEN ", 5)){ if(parsehostname((char *)buf+5, param, 21)){RETURN(803);} if(param->remsock != INVALID_SOCKET) { so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); param->remsock = INVALID_SOCKET; } if((res = (*param->srv->authfunc)(param))) {RETURN(res);} param->ctrlsocksrv = param->remsock; if(socksend(param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);} status = 1; } else if (!strncasecmp((char *)buf, "USER ", 5)){ if(parseconnusername((char *)buf +5, param, 0, 21)){RETURN(804);} if(!status){ if((res = (*param->srv->authfunc)(param))) {RETURN(res);} param->ctrlsocksrv = param->remsock; } if(socksend(param->ctrlsock, (unsigned char *)"331 ok\r\n", 8, conf.timeouts[STRING_S])!=8) {RETURN (807);} status = 2; } else if (!strncasecmp((char *)buf, "PASS ", 5)){ param->extpassword = (unsigned char *)mystrdup((char *)buf+5); inbuf = BUFSIZE; res = ftplogin(param, (char *)buf, &inbuf); param->res = res; if(inbuf && inbuf != BUFSIZE && socksend(param->ctrlsock, buf, inbuf, conf.timeouts[STRING_S])!=inbuf) {RETURN (807);} if(!res) status = 3; sprintf((char *)buf, "%.64s@%.128s%c%hu", param->extusername, param->hostname, (ntohs(param->sins.sin_port)==21)?0:':', ntohs(param->sins.sin_port)); req = mystrdup((char *)buf); #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlereqfilters(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(877); } #endif } else if (status >= 3 && ( (!strncasecmp((char *)buf, "PASV", 4) && (pasv = 1)) || (!strncasecmp((char *)buf, "PORT ", 5) && !(pasv = 0)) )){ #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(878); } #endif if(sc != INVALID_SOCKET) { so._shutdown(sc, SHUT_RDWR); so._closesocket(sc); sc = INVALID_SOCKET; } if(ss != INVALID_SOCKET) { so._shutdown(ss, SHUT_RDWR); so._closesocket(ss); ss = INVALID_SOCKET; } if(clidatasock != INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; } if ((clidatasock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);} sasize = sizeof(struct sockaddr_in); if(so._getsockname(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(824);} param->sinc.sin_port = 0; if(so._bind(clidatasock, (struct sockaddr *)¶m->sinc, sasize)){RETURN(822);} if (pasv) { if(so._listen(clidatasock, 1)) {RETURN(823);} if(so._getsockname(clidatasock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(824);} sprintf((char *)buf, "227 OK (%u,%u,%u,%u,%u,%u)\r\n", (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[0]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[1]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[2]), (unsigned)(((unsigned char *)(¶m->sinc.sin_addr.s_addr))[3]), (unsigned)(((unsigned char *)(¶m->sinc.sin_port))[0]), (unsigned)(((unsigned char *)(¶m->sinc.sin_port))[1]) ); } else { unsigned long b1, b2, b3, b4; unsigned short b5, b6; if(sscanf((char *)buf+5, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) {RETURN(828);} param->sinc.sin_family = AF_INET; param->sinc.sin_port = htons((unsigned short)((b5<<8)^b6)); param->sinc.sin_addr.s_addr = htonl((b1<<24)^(b2<<16)^(b3<<8)^b4); if(so._connect(clidatasock, (struct sockaddr *)¶m->sinc, sasize)) { so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; RETURN(826); } sprintf(buf, "200 OK\r\n"); } #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterssrv(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(879); } #endif if(socksend(param->ctrlsock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S])!=(int)strlen((char *)buf)) {RETURN (825);} status = 4; } else if (status == 4 && ( !(strncasecmp((char *)buf, "RETR ", 5) && (param->operation = FTP_GET)) || !(strncasecmp((char *)buf, "LIST", 4) && (param->operation = FTP_LIST))|| !(strncasecmp((char *)buf, "NLST ", 5) && (param->operation = FTP_LIST)) || !(strncasecmp((char *)buf, "MLSD", 4) && (param->operation = FTP_LIST)) || !(strncasecmp((char *)buf, "APPE ", 5) && (param->operation = FTP_PUT)) || !(strncasecmp((char *)buf, "STOR ", 5) && (param->operation = FTP_PUT)) )){ int arg = (buf[4] && buf[5])? 1:0; int ressent = 0; #ifndef WITHMAIN { int action, reqbufsize, reqsize; reqbufsize = BUFSIZE; reqsize = (int)strlen(buf) + 1; action = handlehdrfilterscli(param, &buf, &reqbufsize, 0, &reqsize); if(action == HANDLED){ RETURN(0); } if(action != PASS) RETURN(880); } #endif if(clidatasock == INVALID_SOCKET) { RETURN (829);} if(pasv){ memset(&fds, 0, sizeof(fds)); fds.fd = clidatasock; fds.events = POLLIN; res = so._poll (&fds, 1, conf.timeouts[STRING_L]*1000); if(res != 1) { RETURN(857); } sasize = sizeof(struct sockaddr_in); ss = so._accept(clidatasock, (struct sockaddr *)¶m->sinc, &sasize); if (ss == INVALID_SOCKET) { RETURN (858);} so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = ss; ss = INVALID_SOCKET; } if(clidatasock == INVALID_SOCKET){RETURN(828);} req = mystrdup((char *)buf); buf[4] = 0; status = 3; ss = ftpcommand(param, buf, arg? buf+5 : NULL); if (ss == INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); clidatasock = INVALID_SOCKET; if(socksend(param->ctrlsock, (unsigned char *)"550 err\r\n", 9, conf.timeouts[STRING_S])!=9) {RETURN (831);} continue; } if(socksend(param->ctrlsock, (unsigned char *)"125 data\r\n", 10, conf.timeouts[STRING_S]) != 10) { param->remsock = INVALID_SOCKET; RETURN (832); } if(param->srvoffset < param->srvinbuf)while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', 0)) > 3){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);} if(isnumber(*buf) && buf[3] != '-') { ressent = 1; break; } } sc = param->remsock; param->remsock = ss; so._setsockopt(param->remsock, SOL_SOCKET, SO_LINGER, (unsigned char *)&lg, sizeof(lg)); so._setsockopt(clidatasock, SOL_SOCKET, SO_LINGER, (unsigned char *)&lg, sizeof(lg)); param->clisock = clidatasock; res = sockmap(param, conf.timeouts[CONNECTION_S]); if(param->remsock != INVALID_SOCKET) { so._shutdown (param->remsock, SHUT_RDWR); so._closesocket(param->remsock); } if(param->clisock != INVALID_SOCKET) { so._shutdown (param->clisock, SHUT_RDWR); so._closesocket(param->clisock); } param->clisock = param->ctrlsock; param->remsock = sc; sc = INVALID_SOCKET; ss = INVALID_SOCKET; clidatasock = INVALID_SOCKET; if(!ressent){ while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 3){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN(833);} if(isnumber(*buf) && buf[3] != '-') break; } if(i < 3) {RETURN(834);} } } else { if(status < 3) { if(socksend(param->remsock, (unsigned char *)"530 login\r\n", 11, conf.timeouts[STRING_S])!=1) {RETURN (810);} continue; } if(!strncasecmp((char *)buf, "QUIT", 4)) status = 5; if(!strncasecmp((char *)buf, "CWD ", 4)) req = mystrdup((char *)buf); i = (int)strlen((char *)buf); buf[i++] = '\r'; buf[i++] = '\n'; if(socksend(param->remsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (811);} param->statscli += i; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, buf, BUFSIZE, '\n', conf.timeouts[STRING_L])) > 0){ if(socksend(param->ctrlsock, buf, i, conf.timeouts[STRING_S])!=i) {RETURN (812);} if(i > 4 && isnumber(*buf) && buf[3] != '-') break; } if(status == 5) {RETURN (0);} if(i < 3) {RETURN (813);} } sasize = sizeof(struct sockaddr_in); if(so._getpeername(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize)){RETURN(819);} if(req && (param->statscli || param->statssrv)){ (*param->srv->logfunc)(param, (unsigned char *)req); } } CLEANRET: if(sc != INVALID_SOCKET) { so._shutdown(sc, SHUT_RDWR); so._closesocket(sc); } if(ss != INVALID_SOCKET) { so._shutdown(ss, SHUT_RDWR); so._closesocket(ss); } if(clidatasock != INVALID_SOCKET) { so._shutdown(clidatasock, SHUT_RDWR); so._closesocket(clidatasock); } sasize = sizeof(struct sockaddr_in); so._getpeername(param->ctrlsock, (struct sockaddr *)¶m->sinc, &sasize); if(param->res != 0 || param->statscli || param->statssrv ){ (*param->srv->logfunc)(param, (unsigned char *)((req && (param->res > 802))? req:NULL)); } if(req) myfree(req); if(buf) myfree(buf); freeparam(param); return (NULL); }
void * adminchild(struct clientparam* param) { int i, res; char * buf; char username[256]; char *sb; char *req = NULL; struct printparam pp; int contentlen = 0; int isform = 0; pp.inbuf = 0; pp.cp = param; buf = myalloc(LINESIZE); if(!buf) {RETURN(555);} i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S]); if(i<5 || ((buf[0]!='G' || buf[1]!='E' || buf[2]!='T' || buf[3]!=' ' || buf[4]!='/') && (buf[0]!='P' || buf[1]!='O' || buf[2]!='S' || buf[3]!='T' || buf[4]!=' ' || buf[5]!='/'))) { RETURN(701); } buf[i] = 0; sb = strchr(buf+5, ' '); if(!sb){ RETURN(702); } *sb = 0; req = mystrdup(buf + ((*buf == 'P')? 6 : 5)); while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){ buf[i] = 0; if(i > 19 && (!strncasecmp(buf, "authorization", 13))){ sb = strchr(buf, ':'); if(!sb)continue; ++sb; while(isspace(*sb))sb++; if(!*sb || strncasecmp(sb, "basic", 5)){ continue; } sb+=5; while(isspace(*sb))sb++; i = de64((unsigned char *)sb, (unsigned char *)username, 255); if(i<=0)continue; username[i] = 0; sb = strchr((char *)username, ':'); if(sb){ *sb = 0; if(param->password)myfree(param->password); param->password = (unsigned char *)mystrdup(sb+1); } if(param->username) myfree(param->username); param->username = (unsigned char *)mystrdup(username); continue; } else if(i > 15 && (!strncasecmp(buf, "content-length:", 15))){ sb = buf + 15; while(isspace(*sb))sb++; contentlen = atoi(sb); } else if(i > 13 && (!strncasecmp(buf, "content-type:", 13))){ sb = buf + 13; while(isspace(*sb))sb++; if(!strncasecmp(sb, "x-www-form-urlencoded", 21)) isform = 1; } } param->operation = ADMIN; if(isform && contentlen) { printstr(&pp, "HTTP/1.0 100 Continue\r\n\r\n"); stdpr(&pp, NULL, 0); } res = (*param->srv->authfunc)(param); if(res && res != 10) { printstr(&pp, authreq); RETURN(res); } if(param->srv->singlepacket || param->redirected){ if(*req == 'C') req[1] = 0; else *req = 0; } sprintf(buf, ok, conf.stringtable?(char *)conf.stringtable[2]:"3proxy", conf.stringtable?(char *)conf.stringtable[2]:"3[APA3A] tiny proxy", conf.stringtable?(char *)conf.stringtable[3]:""); if(*req != 'S') printstr(&pp, buf); switch(*req){ case 'C': printstr(&pp, counters); { struct trafcount *cp; int num = 0; for(cp = conf.trafcounter; cp; cp = cp->next, num++){ int inbuf = 0; if(cp->ace && (param->srv->singlepacket || param->redirected)){ if(!ACLmatches(cp->ace, param))continue; } if(req[1] == 'S' && atoi(req+2) == num) cp->disabled=0; if(req[1] == 'D' && atoi(req+2) == num) cp->disabled=1; inbuf += sprintf(buf, "<tr>" "<td>%s</td><td><A HREF=\'/C%c%d\'>%s</A></td><td>", (cp->comment)?cp->comment:" ", (cp->disabled)?'S':'D', num, (cp->disabled)?"NO":"YES" ); if(!cp->ace || !cp->ace->users){ inbuf += sprintf(buf+inbuf, "<center>ANY</center>"); } else { inbuf += printuserlist(buf+inbuf, LINESIZE-800, cp->ace->users, ",<br />\r\n"); } inbuf += sprintf(buf+inbuf, "</td><td>"); if(!cp->ace || !cp->ace->src){ inbuf += sprintf(buf+inbuf, "<center>ANY</center>"); } else { inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->src, ",<br />\r\n"); } inbuf += sprintf(buf+inbuf, "</td><td>"); if(!cp->ace || !cp->ace->dst){ inbuf += sprintf(buf+inbuf, "<center>ANY</center>"); } else { inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->dst, ",<br />\r\n"); } inbuf += sprintf(buf+inbuf, "</td><td>"); if(!cp->ace || !cp->ace->ports){ inbuf += sprintf(buf+inbuf, "<center>ANY</center>"); } else { inbuf += printportlist(buf+inbuf, LINESIZE-128, cp->ace->ports, ",<br />\r\n"); } if(cp->type == NONE) { inbuf += sprintf(buf+inbuf, "</td><td colspan=\'6\' align=\'center\'>exclude from limitation</td></tr>\r\n" ); } else { inbuf += sprintf(buf+inbuf, "</td><td>%.3f</td>" "<td>MB%s</td>" "<td>%.3f MB</td>" "<td>%s</td>", (1024.0 * (float)cp->traflimgb) + (float)cp->traflim/1048576.0, rotations[cp->type], (1024.0 * (float)cp->trafgb) + (float)cp->traf/1048576.0, cp->cleared?ctime(&cp->cleared):"never" ); inbuf += sprintf(buf + inbuf, "<td>%s</td>" "<td>%i</td>" "</tr>\r\n", cp->updated?ctime(&cp->updated):"never", cp->number ); } printstr(&pp, buf); } } printstr(&pp, counterstail); break; case 'R': conf.needreload = 1; printstr(&pp, "<h3>Reload scheduled</h3>"); break; case 'S': { if(req[1] == 'X'){ printstr(&pp, style); break; } printstr(&pp, xml); printval(conf.services, TYPE_SERVER, 0, &pp); printstr(&pp, postxml); } break; case 'F': { FILE *fp; char buf[256]; fp = confopen(); if(!fp){ printstr(&pp, "<h3><font color=\"red\">Failed to open config file</font></h3>"); break; } printstr(&pp, "<h3>Please be careful editing config file remotely</h3>"); printstr(&pp, "<form method=\"POST\" action=\"/U\"><textarea cols=\"80\" rows=\"30\" name=\"conffile\">"); while(fgets(buf, 256, fp)){ printstr(&pp, buf); } if(!writable) fclose(fp); printstr(&pp, "</textarea><br><input type=\"Submit\"></form>"); break; } case 'U': { int l=0; int error = 0; if(!writable || fseek(writable, 0, 0)){ error = 1; } while((i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, LINESIZE - 1, '+', conf.timeouts[STRING_S])) > 0){ if(i > (contentlen - l)) i = (contentlen - l); buf[i] = 0; if(!l){ if(strncasecmp(buf, "conffile=", 9)) error = 1; } if(!error){ decodeurl((unsigned char *)buf, 1); fprintf(writable, "%s", l? buf : buf + 9); } l += i; if(l >= contentlen) break; } if(writable && !error){ fflush(writable); #ifndef _WINCE ftruncate(fileno(writable), ftell(writable)); #endif } printstr(&pp, error? "<h3><font color=\"red\">Config file is not writable</font></h3>Make sure you have \"writable\" command in configuration file": "<h3>Configuration updated</h3>"); } break; default: printstr(&pp, (char *)conf.stringtable[WEBBANNERS]); break; } if(*req != 'S') printstr(&pp, tail); CLEANRET: printstr(&pp, NULL); if(buf) myfree(buf); (*param->srv->logfunc)(param, (unsigned char *)req); if(req)myfree(req); freeparam(param); return (NULL); }
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; } }
int ftplogin(struct clientparam *param, char *nbuf, int *innbuf) { char tbuf[256]; int i; char *buf; int len; int res; buf = nbuf?nbuf:tbuf; len = nbuf?*innbuf:sizeof(tbuf); if(innbuf)*innbuf = 0; if(len < 140) return 707; while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } if(i < 3) return 706; buf[i] = 0; if(atoi(buf)/100 != 2) { *innbuf = i; return 702; } sprintf(buf, "USER %.128s\r\n", param->extusername?param->extusername:(unsigned char *)"anonymous"); if((int)socksend(param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){ return 703; } param->statscli64 += (int)strlen(buf); param->nwrites++; while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0 && (i < 3 || !isnumber(*buf) || buf[3] == '-')){ } if(i < 3) return 704; buf[i] = 0; res = atoi(buf)/100; if(res == 3){ sprintf(buf, "PASS %.128s\r\n", param->extusername? (param->extpassword? param->extpassword:(unsigned char *)"") :(unsigned char *)"3proxy@"); res = (int)strlen(buf); if((int)socksend(param->remsock, (unsigned char *)buf, res, conf.timeouts[STRING_S]) != (int)strlen(buf)){ return 705; } param->statscli64 += res; param->nwrites++; while((i = sockgetlinebuf(param, SERVER, (unsigned char *)buf, len - 1, '\n', conf.timeouts[STRING_L])) > 0){ buf[i] = 0; res = (i>3 && buf[3] != '-')? atoi(buf)/100 : 0; if(res || (nbuf && (len-i) > 256 && i > 3)) { buf += i; len -= i; if(innbuf)*innbuf += i; } if(res) break; } if(i < 3) { return 701; } } if(res != 2) { return 700; } return 0; }
void * proxychild(struct clientparam* param) { int res=0, i=0; unsigned char* buf = NULL, *newbuf; int inbuf; int bufsize; unsigned reqlen = 0; unsigned char *sb=NULL, *sg=NULL, *se=NULL, *sp=NULL, *req=NULL, *su=NULL, *ss = NULL; unsigned char *ftpbase=NULL; unsigned char username[1024]; int keepalive = 0; uint64_t contentlength64 = 0; int hascontent =0; int isconnect = 0; int redirect = 0; int prefix = 0, ckeepalive=0; int ftp = 0; int anonymous; int sleeptime = 0; int reqsize, reqbufsize; int authenticate; struct pollfd fds[2]; SOCKET ftps; char ftpbuf[FTPBUFSIZE]; int inftpbuf = 0; #ifndef WITHMAIN FILTER_ACTION action; #endif if(!(buf = myalloc(BUFSIZE))) {RETURN(21);} bufsize = BUFSIZE; anonymous = param->srv->singlepacket; for(;;){ memset(buf, 0, bufsize); inbuf = 0; if(keepalive && (param->cliinbuf == param->clioffset) && (param->remsock != INVALID_SOCKET)){ memset(fds, 0, sizeof(fds)); fds[0].fd = param->clisock; fds[0].events = POLLIN; fds[1].fd = param->remsock; fds[1].events = POLLIN; res = so._poll(fds, 2, conf.timeouts[STRING_S]*1000); if(res<=0) { RETURN(555); } if((fds[1].revents & (POLLIN|POLLHUP|POLLERR|POLLNVAL))) { if(param->transparent || (!param->redirected && param->redirtype == R_HTTP)) RETURN(555); ckeepalive = 0; so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); param->remsock = INVALID_SOCKET; param->redirected = 0; param->redirtype = 0; } } i = sockgetlinebuf(param, CLIENT, buf, LINESIZE - 1, '\n', conf.timeouts[STRING_L]); if(i<=0) { RETURN((keepalive)?555:(i)?507:508); } if (i==2 && buf[0]=='\r' && buf[1]=='\n') continue; buf[i] = 0; if(req) { if(!param->transparent && !param->srv->transparent && param->redirtype != R_HTTP && (i<=prefix || strncasecmp((char *)buf, (char *)req, prefix))){ ckeepalive = 0; if(param->remsock != INVALID_SOCKET){ so._shutdown(param->remsock, SHUT_RDWR); so._closesocket(param->remsock); } param->remsock = INVALID_SOCKET; param->redirected = 0; param->redirtype = 0; } myfree(req); } req = (unsigned char *)mystrdup((char *)buf); if(!req){RETURN(510);} if(i<10) { RETURN(511); } if(buf[i-3] == '1') keepalive = 2; if((isconnect = !strncasecmp((char *)buf, "CONNECT", 7))) keepalive = 2; if ((sb=(unsigned char *)(unsigned char *)strchr((char *)buf, ' ')) == NULL) {RETURN(512);} ss = ++sb; if(!isconnect) { if (!strncasecmp((char *)sb, "http://", 7)) { sb += 7; } else if (!strncasecmp((char *)sb, "ftp://", 6)) { ftp = 1; sb += 6; } else if(*sb == '/') { param->transparent = 1; } else { RETURN (513); } } else { if ((se=(unsigned char *)(unsigned char *)strchr((char *)sb, ' ')) == NULL || sb==se) {RETURN (514);} *se = 0; } if(!param->transparent || isconnect) { if(!isconnect) { if ((se=(unsigned char *)(unsigned char *)strchr((char *)sb, '/')) == NULL || sb==se || !(sg=(unsigned char *)strchr((char *)sb, ' '))) {RETURN (515);} if(se > sg) se=sg; *se = 0; } prefix = (int)(se - buf); su = (unsigned char*)strrchr((char *)sb, '@'); if(su) { su = mystrdup(sb); decodeurl(su, 0); parseconnusername((char *)su, (struct clientparam *)param, 1, (unsigned short)((ftp)?21:80)); myfree(su); } else parsehostname((char *)sb, (struct clientparam *)param, (unsigned short)((ftp)? 21:80)); if(!isconnect){ if(se==sg)*se-- = ' '; *se = '/'; memmove(ss, se, i - (se - sb) + 1); } } reqlen = i = (int)strlen((char *)buf); if(!strncasecmp((char *)buf, "CONNECT", 7))param->operation = HTTP_CONNECT; else if(!strncasecmp((char *)buf, "GET", 3))param->operation = (ftp)?FTP_GET:HTTP_GET; else if(!strncasecmp((char *)buf, "PUT", 3))param->operation = (ftp)?FTP_PUT:HTTP_PUT; else if(!strncasecmp((char *)buf, "POST", 4)||!strncasecmp((char *)buf, "BITS_POST", 9))param->operation = HTTP_POST; else if(!strncasecmp((char *)buf, "HEAD", 4))param->operation = HTTP_HEAD; else param->operation = HTTP_OTHER; do { buf[inbuf+i]=0; /*printf("Got: %s\n", buf+inbuf);*/ #ifndef WITHMAIN if(i > 25 && !param->srv->transparent && (!strncasecmp((char *)(buf+inbuf), "proxy-authorization", 19))){ sb = (unsigned char *)strchr((char *)(buf+inbuf), ':'); if(!sb)continue; ++sb; while(isspace(*sb))sb++; if(!*sb) continue; if(!strncasecmp((char *)sb, "basic", 5)){ sb+=5; while(isspace(*sb))sb++; i = de64(sb, username, 255); if(i<=0)continue; username[i] = 0; sb = (unsigned char *)strchr((char *)username, ':'); if(sb){ *sb = 0; if(param->password)myfree(param->password); param->password = (unsigned char *)mystrdup((char *)sb+1); param->pwtype = 0; } if(param->username)myfree(param->username); param->username = (unsigned char *)mystrdup((char *)username); continue; } #ifndef NOCRYPT if(param->srv->usentlm && !strncasecmp((char *)sb, "ntlm", 4)){ sb+=4; while(isspace(*sb))sb++; i = de64(sb, username, 1023); if(i<=16)continue; username[i] = 0; if(strncasecmp((char *)username, "NTLMSSP", 8)) continue; if(username[8] == 1) { while( (i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, '\n', conf.timeouts[STRING_S])) > 2){ if(i> 15 && (!strncasecmp((char *)(buf), "content-length", 14))){ buf[i]=0; sscanf((char *)buf + 15, "%"PRINTF_INT64_MODIFIER"u", &contentlength64); } } while( contentlength64 > 0 && (i = sockgetlinebuf(param, CLIENT, buf, (BUFSIZE < contentlength64)? BUFSIZE - 1:(int)contentlength64, '\n', conf.timeouts[STRING_S])) > 0){ if ((uint64_t)i > contentlength64) break; contentlength64-=i; } contentlength64 = 0; if(param->password)myfree(param->password); param->password = myalloc(32); param->pwtype = 2; i = (int)strlen(proxy_stringtable[13]); memcpy(buf, proxy_stringtable[13], i); genchallenge(param, (char *)param->password, (char *)buf + i); memcpy(buf + strlen((char *)buf), "\r\n\r\n", 5); socksend(param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]); ckeepalive = keepalive = 1; goto REQUESTEND; } if(username[8] == 3 && param->pwtype == 2 && i>=80) { unsigned offset, len; len = username[20] + (((unsigned)username[21]) << 8); offset = username[24] + (((unsigned)username[25]) << 8); if(len != 24 || len + offset > (unsigned)i) continue; memcpy(param->password + 8, username + offset, 24); len = username[36] + (((unsigned)username[37]) << 8); offset = username[40] + (((unsigned)username[41]) << 8); if(len> 255 || len + offset > (unsigned)i) continue; if(param->username) myfree(param->username); unicode2text((char *)username+offset, (char *)username+offset, (len>>1)); param->username = (unsigned char *)mystrdup((char *)username+offset); } continue; } #endif }
void * dnsprchild(struct clientparam* param) { unsigned long ip = 0; unsigned char *bbuf; unsigned char *buf, *s1, *s2; char * host = NULL; unsigned char c; SASIZETYPE size; int res, i; int len; unsigned type=0; unsigned ttl; unsigned char addr[16]; #ifdef _WIN32 unsigned long ul = 1; #endif if(!(bbuf = myalloc(BUFSIZE+2))){ param->srv->fds.events = POLLIN; RETURN (21); } buf = bbuf+2; size = sizeof(param->sincr); i = so._recvfrom(param->srv->srvsock, buf, BUFSIZE, 0, (struct sockaddr *)¶m->sincr, &size); size = sizeof(param->sinsl); getsockname(param->srv->srvsock, (struct sockaddr *)¶m->sincl, &size); #ifdef _WIN32 if((param->clisock=so._socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); } ioctlsocket(param->clisock, FIONBIO, &ul); if(so._setsockopt(param->clisock, SOL_SOCKET, SO_REUSEADDR, (unsigned char *)&ul, sizeof(int))) {RETURN(820);}; if(so._bind(param->clisock,(struct sockaddr *)¶m->sincl,sizeof(param->sincl))) { RETURN(822); } #else param->clisock = param->srv->srvsock; #endif param->srv->fds.events = POLLIN; if(i < 0) { RETURN(813); } buf[BUFSIZE - 1] = 0; if(i<=13 || i>1000){ RETURN (814); } param->operation = DNSRESOLVE; if((res = (*param->srv->authfunc)(param))) {RETURN(res);} if(buf[4]!=0 || buf[5]!=1) RETURN(816); for(len = 12; len<i; len+=(c+1)){ c = buf[len]; if(!c)break; buf[len] = '.'; } if(len > (i-4)) {RETURN(817);} host = mystrdup((char *)buf+13); if(!host) {RETURN(21);} for(s2 = buf + 12; (s1 = (unsigned char *)strchr((char *)s2 + 1, '.')); s2 = s1)*s2 = (unsigned char)((s1 - s2) - 1); *s2 = (len - (int)(s2 - buf)) - 1; type = ((unsigned)buf[len+1])*256 + (unsigned)buf[len+2]; if((type==0x01 || type==0x1c) && !param->srv->singlepacket){ ip = udpresolve((type==0x1c)?AF_INET6:AF_INET, (unsigned char *)host, addr, &ttl, param, 0); } len+=5; if(ip){ buf[2] = 0x85; buf[3] = 0x80; buf[6] = 0; buf[7] = 1; buf[8] = buf[9] = buf[10] = buf[11] = 0; memset(buf+len, 0, 16); buf[len] = 0xc0; buf[len+1] = 0x0c; buf[len+3] = type; buf[len+5] = 1; ttl = htonl(ttl); memcpy(buf + len + 6, &ttl, 4); buf[len+11] = type==1? 4:16; memcpy(buf+len+12,(void *)&addr,type==1? 4:16); len+=(type==1?16:28); } else if(type == 0x0c) { unsigned a, b, c, d; sscanf(host, "%u.%u.%u.%u", &a, &b, &c, &d); ip = htonl((d<<24) ^ (c<<16) ^ (b<<8) ^ a); if(*SAFAMILY(¶m->sincl) == AF_INET && ip == *(unsigned long*)SAADDR(¶m->sincl)){ buf[2] = 0x85; buf[3] = 0x80; buf[6] = 0; buf[7] = 1; buf[8] = buf[9] = buf[10] = buf[11] = 0; memset(buf+len, 0, 20); buf[len] = 0xc0; buf[len+1] = 0x0c; buf[len+3] = 0x0c; buf[len+5] = 1; ttl = htonl(3600); memcpy(buf + len + 6, &ttl, 4); buf[len+11] = 7; buf[len+12] = 6; memcpy(buf+len+13,(void *)"3proxy",6); len+=20; } else ip = 0; } if(!ip && numservers){ if((param->remsock=so._socket(SASOCK(&nservers[0].addr), nservers[0].usetcp? SOCK_STREAM:SOCK_DGRAM, nservers[0].usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); } memset(¶m->sinsl, 0, sizeof(param->sinsl)); *SAFAMILY(¶m->sinsl) = *SAFAMILY(&nservers[0].addr); if(so._bind(param->remsock,(struct sockaddr *)¶m->sinsl,sizeof(param->sinsl))) { RETURN(819); } memcpy(¶m->sinsr, &nservers[0].addr, sizeof(param->sinsr)); if(nservers[0].usetcp) { if(so._connect(param->remsock,(struct sockaddr *)¶m->sinsr,sizeof(param->sinsr))) RETURN(830); buf-=2; *(unsigned short*)buf = htons(i); i+=2; } else { #ifdef _WIN32 /* ioctlsocket(param->remsock, FIONBIO, &ul); */ #else /* fcntl(param->remsock,F_SETFL,O_NONBLOCK); */ #endif } if(socksendto(param->remsock, (struct sockaddr *)¶m->sinsr, buf, i, conf.timeouts[SINGLEBYTE_L]*1000) != i){ RETURN(820); } param->statscli64 += i; param->nwrites++; len = sockrecvfrom(param->remsock, (struct sockaddr *)¶m->sinsr, buf, BUFSIZE, 15000); if(len <= 13) { RETURN(821); } param->statssrv64 += len; param->nreads++; if(nservers[0].usetcp) { unsigned short us; us = ntohs(*(unsigned short *)buf); if(us > 4096) RETURN(833); buf += 2; len -= 2; if(len < us) len += sockgetlinebuf(param, SERVER, buf+len, us - len, 0, conf.timeouts[SINGLEBYTE_L]); if(len != us) RETURN(832); } if(buf[6] || buf[7]){ if(socksendto(param->clisock, (struct sockaddr *)¶m->sincr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ RETURN(822); } RETURN(0); } } if(!ip) { buf[2] = 0x85; buf[3] = 0x83; } res = socksendto(param->clisock, (struct sockaddr *)¶m->sincr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000); if(res != len){RETURN(819);} if(!ip) {RETURN(888);} CLEANRET: if(param->res!=813){ sprintf((char *)buf, "%04x/%s/", (unsigned)type, host?host:""); if(ip && type == 0x01 || type == 0x1c){ myinet_ntop(type == 0x01? AF_INET:AF_INET6, addr, buf+strlen(buf), 64); } (*param->srv->logfunc)(param, buf); } if(bbuf)myfree(bbuf); if(host)myfree(host); #ifndef _WIN32 param->clisock = INVALID_SOCKET; #endif freeparam(param); return (NULL); }