Esempio n. 1
0
static int h_external(int argc, unsigned char ** argv){
	int res;
#ifndef NOIPV6
	struct sockaddr_in6 sa6;
	memset(&sa6, 0, sizeof(sa6));
	res = getip46(46, argv[1], (struct sockaddr *)&sa6);
	if(!res) return 1; 
	if (*SAFAMILY(&sa6)==AF_INET) conf.extsa = sa6;
	else conf.extsa6 = sa6;
#else
	res = getip46(46, argv[1], (struct sockaddr *)&conf.extsa);
	if(!res) return 1; 
#endif
	return 0;
}
Esempio n. 2
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;
	
}
Esempio n. 3
0
int scanipl(unsigned char *arg, struct iplist *dst){
#ifndef NOIPV6
	struct sockaddr_in6 sa;
#else
	struct sockaddr_in sa;
#endif
        char * slash, *dash;
	int masklen, addrlen;
	if((slash = strchr((char *)arg, '/'))) *slash = 0;
	if((dash = strchr((char *)arg,'-'))) *dash = 0;
	
	if(!getip46(46, arg, (struct sockaddr *)&sa)) return 1;
	memcpy(&dst->ip_from, SAADDR(&sa), SAADDRLEN(&sa));
	dst->family = *SAFAMILY(&sa);
	if(dash){
		if(!getip46(46, (unsigned char *)dash+1, (struct sockaddr *)&sa)) return 2;
		memcpy(&dst->ip_to, SAADDR(&sa), SAADDRLEN(&sa));
		if(*SAFAMILY(&sa) != dst->family || memcmp(&dst->ip_to, &dst->ip_from, SAADDRLEN(&sa)) < 0) return 3;
		return 0;
	}
	memcpy(&dst->ip_to, &dst->ip_from, SAADDRLEN(&sa));
	if(slash){
		addrlen = SAADDRLEN(&sa);
		masklen = atoi(slash+1);
		if(masklen < 0 || masklen > (addrlen*8)) return 4;
		else {
			int i, nbytes = masklen / 8, nbits = (8 - (masklen % 8)) % 8;

			for(i = addrlen; i>(nbytes + (nbits > 0)); i--){
				((unsigned char *)&dst->ip_from)[i-1] = 0x00;
				((unsigned char *)&dst->ip_to)[i-1] = 0xff;
			}
			for(;nbits;nbits--){
				((unsigned char *)&dst->ip_from)[nbytes] &= ~(0x01<<(nbits-1));
				((unsigned char *)&dst->ip_to)[nbytes] |= (0x01<<(nbits-1));
			}
			return 0;
		}
	}		
	return 0;
}
Esempio n. 4
0
static int h_nsrecord(int argc, unsigned char **argv){
#ifndef NOIPV6
	struct sockaddr_in6 sa;
#else
	struct sockaddr_in sa;
#endif
	memset(&sa, 0, sizeof(sa));
	if(!getip46(46, argv[2], (struct sockaddr *)&sa)) return 1;

	hashadd(*SAFAMILY(&sa)==AF_INET6?&dns6_table:&dns_table, argv[1], SAADDR(&sa), (time_t)0xffffffff);
	return 0;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
static int h_internal(int argc, unsigned char ** argv){
	getip46(46, argv[1], (struct sockaddr *)&conf.intsa);
	return 0;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
		}
	}