Ejemplo n.º 1
0
Archivo: ftp.c Proyecto: CocoBir/3proxy
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 *)&param->sinsl, &sasize)){return INVALID_SOCKET;}
	sasize = sizeof(param->sinsr);
	if(so._getpeername(param->remsock, (struct sockaddr *)&param->sinsr, &sasize)){return INVALID_SOCKET;}
	rem = param->remsock;
	param->remsock = INVALID_SOCKET;
	param->req = param->sinsr;
	*SAPORT(&param->req) = *SAPORT(&param->sinsr) = htons((unsigned short)((b5<<8)^b6));
	*SAPORT(&param->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(&param->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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
static int h_parent(int argc, unsigned char **argv){
  struct ace *acl = NULL;
  struct chain *chains;

	acl = conf.acl;
	while(acl && acl->next) acl = acl->next;
	if(!acl || (acl->action && acl->action != 2)) {
		fprintf(stderr, "Chaining error: last ACL entry was not \"allow\" or \"redirect\" on line %d\n", linenum);
		return(1);
	}
	acl->action = 2;

	chains = NULL;
	if(!acl->chains) {
		chains = acl->chains = myalloc(sizeof(struct chain));
	}
	else {
		chains = acl->chains;
		while(chains->next)chains = chains->next;
		chains->next = myalloc(sizeof(struct chain));
		chains = chains->next;
	}
	memset(chains, 0, sizeof(struct chain));
	if(!chains){
		fprintf(stderr, "Chainig error: unable to allocate memory for chain\n");
		return(2);
	}
	chains->weight = (unsigned)atoi((char *)argv[1]);
	if(chains->weight == 0 || chains->weight >1000) {
		fprintf(stderr, "Chaining error: bad chain weight %u line %d\n", chains->weight, linenum);
		return(3);
	}
	if(!strcmp((char *)argv[2], "tcp"))chains->type = R_TCP;
	else if(!strcmp((char *)argv[2], "http"))chains->type = R_HTTP;
	else if(!strcmp((char *)argv[2], "connect"))chains->type = R_CONNECT;
	else if(!strcmp((char *)argv[2], "socks4"))chains->type = R_SOCKS4;
	else if(!strcmp((char *)argv[2], "socks5"))chains->type = R_SOCKS5;
	else if(!strcmp((char *)argv[2], "connect+"))chains->type = R_CONNECTP;
	else if(!strcmp((char *)argv[2], "socks4+"))chains->type = R_SOCKS4P;
	else if(!strcmp((char *)argv[2], "socks5+"))chains->type = R_SOCKS5P;
	else if(!strcmp((char *)argv[2], "socks4b"))chains->type = R_SOCKS4B;
	else if(!strcmp((char *)argv[2], "socks5b"))chains->type = R_SOCKS5B;
	else if(!strcmp((char *)argv[2], "pop3"))chains->type = R_POP3;
	else if(!strcmp((char *)argv[2], "ftp"))chains->type = R_FTP;
	else if(!strcmp((char *)argv[2], "admin"))chains->type = R_ADMIN;
	else if(!strcmp((char *)argv[2], "icq"))chains->type = R_ICQ;
	else if(!strcmp((char *)argv[2], "extip"))chains->type = R_EXTIP;
	else if(!strcmp((char *)argv[2], "smtp"))chains->type = R_SMTP;
	else {
		fprintf(stderr, "Chaining error: bad chain type (%s)\n", argv[2]);
		return(4);
	}
	if(!getip46(46, argv[3], (struct sockaddr *)&chains->addr)) return 5;
	*SAPORT(&chains->addr) = htons((unsigned short)atoi((char *)argv[4]));
	if(argc > 5) chains->extuser = (unsigned char *)mystrdup((char *)argv[5]);
	if(argc > 6) chains->extpass = (unsigned char *)mystrdup((char *)argv[6]);
	return 0;
	
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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(&param->sins), SAADDR(&param->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 *)&param->sins,sizeof(param->sins))) {
		param->sins.sin_port = 0;
		if(so._bind(param->remsock,(struct sockaddr *)&param->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 *)&param->sins,  &sasize);
	if(command == 3) {
		param->ctrlsock = param->clisock;
		param->clisock = so._socket(SASOCK(&param->sincr), SOCK_DGRAM, IPPROTO_UDP);
		if(param->clisock == INVALID_SOCKET) {RETURN(11);}
		memcpy(&sin, &param->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 *)&param->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, &param->sins.sin_addr, 4);
					memcpy (buf+8, &param->sins.sin_port, 2);
					socksend(param->clisock, (unsigned char *)buf, 10, conf.timeouts[STRING_S]);
				}
				else {
					memcpy (buf+2, &param->sins.sin_port, 2);
					memcpy (buf+4, &param->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(&param->sincr) || memcmp(SAADDR(&sin), SAADDR(&param->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(&param->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(&param->sins.sin_port, buf+i, 2);
						i+=2;

						sasize = sizeof(param->sins);
						if(len > (int)i){
							if (socksendto(param->remsock, (struct sockaddr *)&param->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(&param->req), SAADDR(&param->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);
}
Ejemplo n.º 8
0
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 *)&param->sincr, ipentry)) {
			break;
		}
	 if(!ipentry) return 0;
	}
	if((acentry->dst && !SAISNULL(&param->req)) || (acentry->dstnames && param->hostname)) {
	 for(ipentry = acentry->dst; ipentry; ipentry = ipentry->next)
		if(IPInentry((struct sockaddr *)&param->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(&param->req)) {
	 for (portentry = acentry->ports; portentry; portentry = portentry->next)
		if(ntohs(*SAPORT(&param->req)) >= portentry->startport &&
			   ntohs(*SAPORT(&param->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;
}
Ejemplo n.º 9
0
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(&param->req) || !*SAPORT(&param->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(&param->sinsr);
				param->sinsr = cur->addr;
				*SAPORT(&param->sinsr) = port;
			}
			else if(SAISNULL(&cur->addr) && *SAPORT(&cur->addr)) *SAPORT(&param->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 *)&param->req):0;
}
Ejemplo n.º 10
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;
	}
}
Ejemplo n.º 11
0
void * sockschild(struct clientparam* param) {
 int res;
 unsigned i=0;
 SOCKET s;
 unsigned size;
 SASIZETYPE sasize;
 unsigned short port = 0;
 unsigned char * buf=NULL;
 unsigned char c;
 unsigned char command=0;
 struct pollfd fds[3];
 int ver=0;
 int havepass = 0;
#ifndef NOIPV6
 struct sockaddr_in6 sin = {AF_INET6};
#else
 struct sockaddr_in sin = {AF_INET};
#endif
 int len;


 param->service = S_SOCKS;

 if(!(buf = myalloc(BUFSIZE))) {RETURN(21);}
 memset(buf, 0, BUFSIZE);
 if ((ver = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5 && ver != 4) {
	RETURN(401);
 } /* version */
 param->service = ver;
 if(ver == 5){
	 if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);} /* nmethods */
	 for (; i; i--) {
		if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
		if (res == 2 && param->srv->needuser) {
			havepass = res;
		}
	 }
	 buf[0] = 5;
	 buf[1] = (param->srv->needuser > 1 && !havepass)? 255 : havepass;
	 if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(401);}
	 if (param->srv->needuser > 1 && !havepass) RETURN(4);
	 if (havepass) {
		if (((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0))) != 1) {
			RETURN(412);
		}
		if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
		if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
		buf[i] = 0;
		if(!param->username)param->username = (unsigned char *)mystrdup((char *)buf);
		if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(445);}
		if (i && (unsigned)(res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != i){RETURN(441);};
		buf[i] = 0;
		if(!param->password)param->password = (unsigned char *)mystrdup((char *)buf);
		buf[0] = 1;
		buf[1] = 0;
		if(socksend(param->clisock, buf, 2, conf.timeouts[STRING_S])!=2){RETURN(481);}
	 }
	 if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) {
		RETURN(421);
         } /* version */
 }
 if( (command = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) < 1 || command > 3){command = 0; RETURN(407);} /* command */
 if(ver == 5){
	 if (sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0) == EOF) {RETURN(447);} /* reserved */
	 c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0); /* atype */
 }
 else {
	if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
	buf[0] = (unsigned char) res;
	if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
	buf[1] = (unsigned char) res;
	port = *(unsigned short*)buf;
	c = 1;
 }
 
 size = 4;
 *SAFAMILY(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET;
 switch(c) {
#ifndef NOIPV6
	case 4:
		if(param->srv->family == 4) RETURN(997);
		size = 16;
		*SAFAMILY(&param->sinsr) = *SAFAMILY(&param->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(&param->sinsr) = *SAFAMILY(&param->req) = AF_INET6;
			memcpy(SAADDR(&param->sinsr), prefix, 12);
			memcpy(12 + (char *)SAADDR(&param->sinsr), buf, 4);
			memcpy(SAADDR(&param->req), prefix, 12);
			memcpy(12 + (char *)SAADDR(&param->req), buf, 4);
		}
		else {
#endif
			memcpy(SAADDR(&param->sinsr), buf, size);
			memcpy(SAADDR(&param->req), buf, size);
#ifndef NOIPV6
		}
#endif
		if(SAISNULL(&param->req)) {
			RETURN(421);
		}
		myinet_ntop(*SAFAMILY(&param->sinsr), SAADDR(&param->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 *) &param->req)) RETURN(100);
		memcpy(&param->sinsr, &param->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(&param->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 *) &param->req)) RETURN(100);
		memcpy(&param->sinsr, &param->req, sizeof(&param->req));
	}
 }

 *SAPORT(&param->sinsr) = *SAPORT(&param->req) = port;
 if(command == 1 && !*SAPORT(&param->sinsr)) {RETURN(421);}
 switch(command) { 
	case 1:
	 param->operation = CONNECT;
	 break;
 	case 2:
	case 3:

#ifndef NOIPV6	 
	 memcpy(&param->sinsl, *SAFAMILY(&param->req)==AF_INET6? (struct sockaddr *)&param->srv->extsa6:(struct sockaddr *)&param->srv->extsa, SASIZE(&param->req)); 
#else
	 memcpy(&param->sinsl, &param->srv->extsa, SASIZE(&param->req)); 
#endif
	 if ((param->remsock=so._socket(SASOCK(&param->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 *)&param->sinsl,SASIZE(&param->sinsl))) {
		*SAPORT(&param->sinsl) = 0;
		if(so._bind(param->remsock,(struct sockaddr *)&param->sinsl,SASIZE(&param->sinsl)))RETURN (12);
#if SOCKSTRACE > 0
fprintf(stderr, "%hu binded to communicate with server\n", *SAPORT(&param->sins));
fflush(stderr);
#endif
	}
	sasize = SASIZE(&param->sinsl);
	so._getsockname(param->remsock, (struct sockaddr *)&param->sinsl,  &sasize);
	if(command == 3) {
		param->ctrlsock = param->clisock;
		param->clisock = so._socket(SASOCK(&param->sincr), SOCK_DGRAM, IPPROTO_UDP);
		if(param->clisock == INVALID_SOCKET) {RETURN(11);}
		memcpy(&sin, &param->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 *)&param->sinsr, &sasize);
				so._closesocket(param->remsock);
				param->remsock = s;
				if(s == INVALID_SOCKET) {
					param->res = 462;
					break;
				}
				if(SAISNULL(&param->req) &&
				 memcmp(SAADDR(&param->req),SAADDR(&param->sinsr),SAADDRLEN(&param->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(&param->sinsr) == AF_INET)?1:4;
					memcpy(buf+4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
					memcpy(buf+4+SAADDRLEN(&param->sinsr), SAPORT(&param->sinsr), 2);
					socksend(param->clisock, buf, 6+SAADDRLEN(&param->sinsr), conf.timeouts[STRING_S]);
				}
				else {
					memcpy (buf+2, SAPORT(&param->sinsr), 2);
					memcpy (buf+4, SAADDR(&param->sinsr), 4);
					socksend(param->clisock, buf, 8, conf.timeouts[STRING_S]);
				}

				param->res = sockmap(param, conf.timeouts[CONNECTION_S]);
				break;
			case 3:
				memcpy(&param->sinsr, &param->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(&param->sincr) || memcmp(SAADDR(&sin), SAADDR(&param->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(&param->sinsr), buf+4, size);
								*SAFAMILY(&param->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 *) &param->sinsr)) RETURN(100);
								break;
							default:
								RETURN(997);
						 }

						memcpy(SAPORT(&param->sinsr), buf+i, 2);
						i+=2;

						sasize = sizeof(param->sinsr);
						if(len > (int)i){
							if(socksendto(param->remsock, (struct sockaddr *)&param->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(&param->sinsl) == AF_INET)?1:4;
						if((len = so._recvfrom(param->remsock, buf+6+SAADDRLEN(&param->sinsl), 65535 - 10, 0, (struct sockaddr *)&param->sinsr, &sasize)) <= 0) {
							param->res = 468;
							break;
						}
						param->statssrv64+=len;
						param->nreads++;
						memcpy(buf+4, SAADDR(&param->sinsr), SAADDRLEN(&param->sinsr));
						memcpy(buf+4+SAADDRLEN(&param->sinsr), SAPORT(&param->sinsr), 2);
						sasize = sizeof(sin);
						if(socksendto(param->clisock, (struct sockaddr *)&sin, buf, len + 6 + SAADDRLEN(&param->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(&param->sinsr)),
			len
	);
fflush(stderr);
#endif

					}
				}
				break;
			default:
				param->res = 417;
				break;
		}
	}