فهرست منبع

Merge remote-tracking branch 'refs/remotes/origin/devel' into devel-logthread

# Conflicts:
#	src/plugins.c
#	src/proxymain.c
#	src/sockmap.c
z3APA3A 5 سال پیش
والد
کامیت
fa4322afee

+ 5 - 5
3proxy.rc

@@ -2,8 +2,8 @@
 
 
 1 VERSIONINFO
-FILEVERSION 0,9,0,0
-PRODUCTVERSION 0,9,0,0
+FILEVERSION 10,0,0,0
+PRODUCTVERSION 10,0,0,0
 FILETYPE 1
 FILESUBTYPE 0x0L
 BEGIN
@@ -14,12 +14,12 @@ BEGIN
             VALUE "Comments", "3proxy - tiny proxy server, http://3proxy.org/\0"
             VALUE "CompanyName", "Vladimir Dubrovin\0"
             VALUE "FileDescription", "3proxy - tiny proxy server\0"
-            VALUE "FileVersion", "0.9-devel-" BUILDDATE "\0"
+            VALUE "FileVersion", "10-devel-" BUILDDATE "\0"
             VALUE "InternalName", "3proxy\0"
-            VALUE "LegalCopyright", "Copyright (C) 2002-2019 Vladimir Dubrovin\0"
+            VALUE "LegalCopyright", "Copyright (C) 2002-2020 Vladimir Dubrovin\0"
             VALUE "OriginalFilename", "3proxy.exe\0"
             VALUE "ProductName", "3proxy\0"
-            VALUE "ProductVersion", "0.9-devel-" BUILDDATE "\0"
+            VALUE "ProductVersion", "10-devel-" BUILDDATE "\0"
         END
     END
     BLOCK "VarFileInfo"

+ 13 - 7
README

@@ -1,5 +1,11 @@
 # 3APA3A 3proxy tiny proxy server
-(c) 2002-2019 by Vladimir '3APA3A' Dubrovin <3proxy@3proxy.ru>
+(c) 2002-2020 by Vladimir '3APA3A' Dubrovin <3proxy@3proxy.ru>
+
+
+Branches:
+Master (stable) branch - 3proxy 0.9 
+Devel branch - 3proxy 10
+
 
 Download: 
 	https://github.com/z3APA3A/3proxy/releases
@@ -58,7 +64,7 @@ Please read doc/html/index.html and man pages.
 	+ Threaded application (no child process).
 	+ Web administration and statistics
 	+ Plugins for functionality extension
-	+ Native 64 bit application
+	+ Native 32/64 bit application
   2. Proxy chaining and network connections
 	+ Can be used as a bridge between client and different proxy type
 	  (e.g. convert incoming HTTP proxy request from client to SOCKSv5
@@ -78,9 +84,8 @@ Please read doc/html/index.html and man pages.
 	+ syslog logging (Unix)
 	+ ODBC logging
 	+ RADIUS accounting
-	+ log file rotation (hourly, daily, weekly, monthly)
-	+ automatic log file comperssion with external archiver (for files)
-	+ automatic removal of older log files
+	+ log file rotation
+	+ automatic log file processing with external archiver (for files)
 	+ Character filtering for log files
 	+ different log files for different servces are supported
   4. Access control
@@ -89,12 +94,13 @@ Please read doc/html/index.html and man pages.
 	(POST, PUT, GET, etc), weekday and daytime.
 	+ ACL-driven (user/source/destination/protocol/weekday/daytime or
 	combined) bandwith limitation for incoming and (!)outgoing trafic.
-	+ ACL-driven (user/source/destination/protocol/weekday/daytime or
-	combined) traffic limitation per day, week or month for incoming and
+	+ ACL-driven traffic limitation per day, week or month for incoming and
 	outgoing traffic
+	+ Connection limitation and ratelimting
 	+ User authentication by username / password
 	+ RADIUS Authentication and Authorization
 	+ User authentication by DNS hostname
+	+ Authentication cache with possibility to limit user to single IP address
 	+ Access control by username/password for SOCKSv5 and HTTP/HTTPS/FTP
 	+ Cleartext or encrypted (crypt/MD5 or NT) passwords.
 	+ Connection redirection

+ 6 - 6
doc/html/howtoe.html

@@ -873,12 +873,12 @@ You can control 3proxy service via "Services" administration ot via "net" comman
 <li>since 0.9
     <li>90 - unexpected system error (should not happen)
     <li>91 - unexpected poll error (should not happen)
-    <li>92 - connection terminated by timeout
-    <li>93 - dirty connection termination by server or client (or network issue) with unsent data
-    <li>94 - clear connection termination by server or client with unsent data
-    <li>95 - dirty connection termination by client (or network issue)
-    <li>96 - dirty connection termination by server (or network issue)
-    <li>97 - dirty connection termination by both client and server (probably network issue)
+    <li>92 - connection terminated by timeout (see timeouts)
+    <li>93 - connection terminated by ratelimit-related timeout or due to errors limit
+    <li>94 - connection termination by server or client with unsent data
+    <li>95 - dirty connection termination by client (or networking issue)
+    <li>96 - dirty connection termination by server (or networking issue)
+    <li>97 - dirty connection termination by both client and server (probably networking issue)
 <li>prior to 0.9:
 		<li>90 - socket error or connection broken
 		<li>91 - TCP/IP common failure

+ 3 - 3
doc/html/howtor.html

@@ -1049,9 +1049,9 @@
     <li>с версии 0.9
     <li>90 - неожиданная системная ошибка (не должно происходить)
     <li>91 - ошибка poll (не должно происходить)
-    <li>92 - соединение прервано по таймауту
-    <li>93 - клиент или сервер &quot;грязно&quot; закрыли соединение или произошла сетевая ошибка, остались неотправленные данные 
-    <li>94 - клиент или сервер &quot;чисто&quot; закрыли соединение или произошла сетевая ошибка, остались неотправленные данные
+    <li>92 - соединение прервано по таймауту на сетевую операцию (см. timeouts)
+    <li>93 - соединение прервано по таймауту связанному с рейтлимитом или из-за превышения числа ошибок
+    <li>94 - клиент или сервер закрыли соединение или произошла сетевая ошибка, остались неотправленные данные
     <li>95 - клиент "грязно" закрыл соединение или сетевая ошибка
     <li>96 - сервер "грязно" закрыл соединение или сетевая ошибка
     <li>97 - клиент и сервер "грязно" закрыли соединение или сетевая ошибка

+ 26 - 0
man/3proxy.cfg.3

@@ -240,6 +240,8 @@ alternate config file. Think twice before using it.
  @ (for Unix) use syslog, filename is used as ident name
 .br
  & use ODBC, filename consists of comma-delimited datasource,username,password (username and password are optional)
+.br
+ radius - use RADIUS for logging
 .br
  LOGTYPE is one of:
 .br
@@ -388,6 +390,28 @@ can use %A as produced archive name and %F as filename.
 .br
  default timeouts 1 5 30 60 180 1800 15 60 15 5
 
+.br
+.B radius 
+<NAS_SECRET> <radius_server_1[:port][/local_address_1]> <radius_server_2[:port][/local_address_2]>
+.br
+ Configures RADIUS servers to be used for logging and authentication (log and auth types
+must be set to radius). port and local address to use with given server may be specified.
+.br
+ Attributes within request: User-Name, Password: (username and password if presented by client),
+Service Type: Authenticate-Only,
+NAS-Port-Type: NAS-Port-Virtual,
+NAS-Port-ID: (proxy service port, e.g. 1080),
+NAS-IPv6-Address / NAS-IP-Address: (proxy interface accessed by client),
+NAS-Identifier: (text identifing proxy, e.g. PROXY or SOCKSv5),
+Framed-IPv6-Address / Framed-IP-Address: (IP address of the client),
+Called-Station-ID: (requested Hostname, if presents),
+Login-Service: (type of request, e.g. 1001 - SOCKS CONNECT, 1010 - HTTP GET, 1013 - HTTP CONNECT),
+Login-TCP-Port: (requested port),
+Login-IPv6-Host / Login-IP-Host: (requested IP). 
+.br
+ Supported reply attributes for authentication:
+Framed-IP-Address / Framed-IPv6-Address (IP to assign to user), Reply-Message.
+Use authcache to speedup authentication. RADIUS feature is currently experimental.
 
 .br
 .B nserver
@@ -503,6 +527,8 @@ NB: there is no any password check, name may be spoofed.
 SOCKSv5, FTP, POP3 and HTTP proxy. 
 .br
  cache - cached authentication, may be used with \'authcache\'.
+.br
+ radius - authentication with RADIUS.
 .br
  Plugins may add additional authentication types.
 

+ 55 - 26
src/auth.c

@@ -676,27 +676,30 @@ int alwaysauth(struct clientparam * param){
 	return res;
 }
 
-int checkACL(struct clientparam * param){
+int checkACL2(struct clientparam * param, int pre){
 	struct ace* acentry;
 
-	if(!param->srv->acl) {
+	acentry = pre?param->srv->preacl:param->srv->acl;
+	if(!acentry) {
 		return 0;
 	}
-	for(acentry = param->srv->acl; acentry; acentry = acentry->next) {
+	for(; 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;
+			if(!pre){
+				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);
 				}
-				dup = *acentry;
-				return handleredirect(param, &dup);
 			}
 			return acentry->action;
 		}
@@ -704,6 +707,19 @@ int checkACL(struct clientparam * param){
 	return 3;
 }
 
+int checkACL(struct clientparam * param){
+	int res;
+	res = checkACL2(param, 1);
+	if(res < 2) return res;
+	return checkACL2(param, 0);
+}
+
+
+int checkpreACL(struct clientparam * param){
+	return checkACL2(param, 1);
+}
+
+
 struct authcache {
 	char * username;
 	char * password;
@@ -771,6 +787,16 @@ int cacheauth(struct clientparam * param){
 	return 4;
 }
 
+int dopreauth(struct clientparam * param){
+	int res = 0;
+
+	if(param->srv && param->srv->authfuncs && param->srv->authfuncs->preauthorize){
+		res = param->srv->authfuncs->preauthorize(param);
+		param->preauthorized = !res;
+		if(res != 1) res = 0;
+	}
+	return res;
+}
 int doauth(struct clientparam * param){
 	int res = 0;
 	struct auth *authfuncs;
@@ -781,7 +807,8 @@ int doauth(struct clientparam * param){
 	for(authfuncs=param->srv->authfuncs; authfuncs; authfuncs=authfuncs->next){
 		res = authfuncs->authenticate?(*authfuncs->authenticate)(param):0;
 		if(!res) {
-			if(authfuncs->authorize &&
+
+			if(!param->preauthorized && authfuncs->authorize &&
 				(res = (*authfuncs->authorize)(param)))
 					return res;
 			if(conf.authcachetype && authfuncs->authenticate && authfuncs->authenticate != cacheauth && param->username && (!(conf.authcachetype&4) || (!param->pwtype && param->password))){
@@ -847,9 +874,11 @@ int doauth(struct clientparam * param){
 int ipauth(struct clientparam * param){
 	int res;
 	unsigned char *username;
+
+	if(param->preauthorized) return (0);
 	username = param->username;
 	param->username = NULL;
-	res = checkACL(param);
+	res = checkACL2(param,0);
 	param->username = username;
 	return res;
 }
@@ -960,20 +989,20 @@ int strongauth(struct clientparam * param){
 int radauth(struct clientparam * param);
 
 struct auth authfuncs[] = {
-	{authfuncs+1, NULL, NULL, ""},
-	{authfuncs+2, ipauth, NULL, "iponly"},
-	{authfuncs+3, userauth, checkACL, "useronly"},
-	{authfuncs+4, dnsauth, checkACL, "dnsname"},
-	{authfuncs+5, strongauth, checkACL, "strong"},
-	{authfuncs+6, cacheauth, checkACL, "cache"},
+	{authfuncs+1, NULL,NULL, NULL, ""},
+	{authfuncs+2, checkpreACL, ipauth, NULL, "iponly"},
+	{authfuncs+3, checkpreACL, userauth, checkACL, "useronly"},
+	{authfuncs+4, checkpreACL, dnsauth, checkACL, "dnsname"},
+	{authfuncs+5, checkpreACL, strongauth, checkACL, "strong"},
+	{authfuncs+6, checkpreACL, cacheauth, checkACL, "cache"},
 #ifndef NORADIUS
 #define AUTHOFFSET 1
-	{authfuncs+7, radauth, checkACL, "radius"},
+	{authfuncs+7, checkpreACL, radauth, checkACL, "radius"},
 #else
 #define AUTHOFFSET 0
 #endif
-	{authfuncs+7+AUTHOFFSET, NULL, NULL, "none"},
-	{NULL, NULL, NULL, ""}
+	{authfuncs+7+AUTHOFFSET, NULL, NULL, NULL, "none"},
+	{NULL, NULL, NULL, NULL, ""}
 };
 
 

+ 1 - 0
src/authradius.c

@@ -578,6 +578,7 @@ int radsend(const char *buf, int total_length, int auth){
 		}
 		else remsock = radiuslist[loop].logsock;
 */
+		so._bind(param->remsock,(struct sockaddr *)&radiuslist[loop].localaddr,SASIZE(&radiuslist[loop].localaddr));
 		len = so._sendto(remsock, (char *)&packet, total_length, 0,
 		      (struct sockaddr *)&saremote, sizeof(saremote));
 		if(len != ntohs(packet.length)){

+ 4 - 1
src/common.c

@@ -292,7 +292,10 @@ int parsehostname(char *hostname, struct clientparam *param, unsigned short port
 
 	if(!hostname || !*hostname)return 2;
 	if(*hostname == '[') se=strchr(hostname, ']');
-	if ( (sp = strchr(se?se:hostname, ':'))  && !strchr(sp+1, ':')) *sp = 0;
+	if (sp = strchr(se?se:hostname, ':')) {
+		if(strchr(sp+1, ':'))sp = NULL;
+		else *sp = 0;
+	}
 	if(se){
 		*se = 0;
 	}

+ 8 - 1
src/conf.c

@@ -481,6 +481,7 @@ static int h_auth(int argc, unsigned char **argv){
 			newau->next = conf.authfuncs;
 			conf.authfuncs = newau;
 			conf.authfuncs->desc = au->desc;
+			conf.authfuncs->preauthorize = au->preauthorize;
 			conf.authfuncs->authenticate = au->authenticate;
 			conf.authfuncs->authorize = au->authorize;
 			break;
@@ -1329,13 +1330,19 @@ static int h_radius(int argc, unsigned char **argv){
 	if(strlen(argv[1]) > 63) argv[1][63] = 0;
 	strcpy(radiussecret, argv[1]);
 	for( nradservers=0; nradservers < MAXRADIUS && nradservers < argc -2; nradservers++){
+		char *s = 0;
+		if(strchr(argv[nradservers + 2], '/')){
+			*s = 0;
+			s++;
+		}
 		if( !getip46(46, argv[nradservers + 2], (struct sockaddr *)&radiuslist[nradservers].authaddr)) return 1;
+		if( s && !getip46(46, s, (struct sockaddr *)&radiuslist[nradservers].localaddr)) return 2;
 		if(!*SAPORT(&radiuslist[nradservers].authaddr))*SAPORT(&radiuslist[nradservers].authaddr) = htons(1812);
 		port = ntohs(*SAPORT(&radiuslist[nradservers].authaddr));
 		radiuslist[nradservers].logaddr = radiuslist[nradservers].authaddr;
  	        *SAPORT(&radiuslist[nradservers].logaddr) = htons(port+1);
 /*
-		bindaddr = conf.intsa;
+		bindaddr = radiuslist[nradservers].localaddr;
 		if ((radiuslist[nradservers].logsock = so._socket(SASOCK(&radiuslist[nradservers].logaddr), SOCK_DGRAM, 0)) < 0) return 2;
 		if (so._bind(radiuslist[nradservers].logsock, (struct sockaddr *)&bindaddr, SASIZE(&bindaddr))) return 3;
 */

+ 5 - 3
src/plugins.c

@@ -74,9 +74,10 @@ struct symbol symbols[] = {
 	{symbols+47, "parsestr", (void *) parsestr},
 	{symbols+48, "make_ace", (void *) make_ace},
 	{symbols+49, "freeacl", (void *) freeacl}
-	{symbols+50, "dolog", (void *) dolog},
-	{symbols+50, "logfuncs", (void *) logfuncs},
-	{symbols+50, "prelog", (void *) prelog},
+	{symbols+50, "checkpreACL", (void *) checkpreACL},
+	{symbols+51, "dolog", (void *) dolog},
+	{symbols+52, "logfuncs", (void *) logfuncs},
+	{symbols+53, "prelog", (void *) prelog},
 	{NULL, "", NULL}
 };
 
@@ -111,6 +112,7 @@ struct pluginlink pluginlink = {
 	ACLmatches,		
 	alwaysauth,
 	checkACL,
+	checkpreACL,
 	nametohash,
 	hashindex,
 	en64,

+ 1 - 0
src/plugins/LdapPlugin/ldapauth.c

@@ -494,6 +494,7 @@ PLUGINAPI int PLUGINCALL start(struct pluginlink * pluginlink,
 
 	
    
+    myalwaysauth.preauthorize = pluginlink->checkpreACL;
     myalwaysauth.authenticate = ldapfunc;
     myalwaysauth.authorize = pluginlink->checkACL;
     myalwaysauth.desc = "ldap";

+ 1 - 0
src/plugins/PamAuth/pamauth.c

@@ -139,6 +139,7 @@ PLUGINAPI int PLUGINCALL start(struct pluginlink * pluginlink, int argc, unsigne
  already_loaded = 1;
     
  pthread_mutex_init(&pam_mutex, NULL);
+ pamauth.preauthorize = pluginlink->checkpreACL;
  pamauth.authenticate = pamfunc;
  pamauth.authorize = pluginlink->checkACL;
  pamauth.desc = "pam";

+ 1 - 0
src/plugins/WindowsAuthentication/WindowsAuthentication.c

@@ -78,6 +78,7 @@ PLUGINAPI int PLUGINCALL WindowsAuthentication(struct pluginlink * pluginlink, i
 		(LPTSTR) tmpbuf, &dlen, &snu)) return 100000 + (int)GetLastError();
 	if(snu != SidTypeGroup && snu != SidTypeAlias && snu != SidTypeWellKnownGroup) return 12;
 	if(!loaded){
+		alwaysauth.preauthorize = pluginlink->checkpreACL;
 		alwaysauth.authenticate = windowsfunc;
 		alwaysauth.authorize = pluginlink->checkACL;
 		alwaysauth.desc = "windows";

+ 5 - 3
src/proxy.h

@@ -173,6 +173,7 @@ int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char
 int doconnect(struct clientparam * param);
 int alwaysauth(struct clientparam * param);
 int ipauth(struct clientparam * param);
+int dopreauth(struct clientparam * param);
 int doauth(struct clientparam * param);
 int strongauth(struct clientparam * param);
 void trafcountfunc(struct clientparam *param);
@@ -236,10 +237,11 @@ int parseusername(char *username, struct clientparam *param, int extpasswd);
 int parseconnusername(char *username, struct clientparam *param, int extpasswd, unsigned short port);
 int ACLmatches(struct ace* acentry, struct clientparam * param);
 int checkACL(struct clientparam * param);
+int checkpreACL(struct clientparam * param);
 extern int havelog;
 unsigned long udpresolve(int af, unsigned char * name, unsigned char * value, unsigned *retttl, struct clientparam* param, int makeauth);
 
-struct ace * copyacl (struct ace *ac);
+void copyacl (struct ace *ac, struct srvparam *srv);
 struct auth * copyauth (struct auth *);
 void * itfree(void *data, void * retval);
 void freeacl(struct ace *ac);
@@ -308,9 +310,9 @@ extern struct commands commandhandlers[];
 
 extern struct radserver {
 #ifdef NOIPV6
-	struct  sockaddr_in authaddr, logaddr;
+	struct  sockaddr_in authaddr, logaddr, localaddr;
 #else
-	struct  sockaddr_in6 authaddr, logaddr;
+	struct  sockaddr_in6 authaddr, logaddr, localaddr;
 #endif
 /*
 	SOCKET logsock;

+ 35 - 13
src/proxymain.c

@@ -1,4 +1,4 @@
-/*
+/*                                                                      
    3APA3A simpliest proxy server
    (c) 2002-2017 by Vladimir Dubrovin <3proxy@3proxy.ru>
 
@@ -34,7 +34,7 @@ void * threadfunc (void *p) {
 		}
 #ifndef WITHMAIN
 		param->req = param->sinsr;
-		if(param->srv->acl) param->res = checkACL(param);
+		if(param->srv->preacl) param->res = checkpreACL(param);
 		if(param->res){
 			dolog(param, (unsigned char *)"Connect back ACL failed");
 			so._closesocket(param->remsock);
@@ -61,7 +61,7 @@ void * threadfunc (void *p) {
 #ifndef _WIN32
 	sigset_t mask;
 	sigfillset(&mask);
-	pthread_sigmask(SIG_SETMASK, &mask, NULL);
+	if(param->srv->service != S_UDPPM)pthread_sigmask(SIG_SETMASK, &mask, NULL);
 #endif
 
 	((struct clientparam *) p)->srv->pf((struct clientparam *)p);
@@ -277,7 +277,7 @@ int MODULEMAINFUNC (int argc, char** argv){
  srv.service = defparam.service = childdef.service;
  
 #ifndef STDMAIN
- srv.acl = copyacl(conf.acl);
+ copyacl(conf.acl, &srv);
  srv.authfuncs = copyauth(conf.authfuncs);
  if(!conf.services){
 	conf.services = &srv;
@@ -286,11 +286,6 @@ int MODULEMAINFUNC (int argc, char** argv){
 	srv.next = conf.services;
 	conf.services = conf.services->prev = &srv;
  }
-#else
- srv.needuser = 0;
- initlog();
-#endif
-
 #ifndef _WIN32
  {
 	sigset_t mask;
@@ -298,6 +293,10 @@ int MODULEMAINFUNC (int argc, char** argv){
 	pthread_sigmask(SIG_SETMASK, &mask, NULL);
  }
 #endif
+#else
+ srv.needuser = 0;
+ initlog();
+#endif
 
  for (i=1; i<argc; i++) {
 	if(*argv[i]=='-') {
@@ -774,6 +773,13 @@ int MODULEMAINFUNC (int argc, char** argv){
 	else {
 		srv.fds.events = 0;
 	}
+	
+#ifndef STDMAIN
+	if((dopreauth(&defparam)) != 0){
+		if(!isudp) so._closesocket(new_sock);
+		continue;
+	}
+#endif
 	if(! (newparam = myalloc (sizeof(defparam)))){
 		if(!isudp) so._closesocket(new_sock);
 		defparam.res = 21;
@@ -784,6 +790,7 @@ int MODULEMAINFUNC (int argc, char** argv){
 	*newparam = defparam;
 	if(defparam.hostname)newparam->hostname=(unsigned char *)mystrdup((char *)defparam.hostname);
 	clearstat(newparam);
+
 	if(!isudp) newparam->clisock = new_sock;
 #ifndef STDMAIN
 	if(makefilters(&srv, newparam) > CONTINUE){
@@ -946,6 +953,7 @@ void srvfree(struct srvparam * srv){
  }
 
  if(srv->acl)freeacl(srv->acl);
+ if(srv->preacl)freeacl(srv->preacl);
  if(srv->authfuncs)freeauth(srv->authfuncs);
 #endif
  pthread_mutex_destroy(&srv->counter_mutex);
@@ -1036,16 +1044,17 @@ struct auth * copyauth (struct auth * authfuncs){
 	return newauth;
 }
 
-struct ace * copyacl (struct ace *ac){
- struct ace * ret = NULL;
+void copyacl (struct ace *ac, struct srvparam *srv){
  struct iplist *ipl;
  struct portlist *pl;
  struct userlist *ul;
  struct chain *ch;
  struct period *pel;
  struct hostname *hst;
+ int preacl = 1;
+ struct ace *acc;
 
- ret = ac = itcopy(ac, sizeof(struct ace));
+ ac = itcopy(ac, sizeof(struct ace));
  for( ; ac; ac = ac->next = itcopy(ac->next, sizeof(struct ace))){
 	ac->src = itcopy(ac->src, sizeof(struct iplist));
 	for(ipl = ac->src; ipl; ipl = ipl->next = itcopy(ipl->next, sizeof(struct iplist)));
@@ -1069,8 +1078,21 @@ struct ace * copyacl (struct ace *ac){
 		if(ch->extpass)ch->extpass = (unsigned char*)mystrdup((char *)ch->extpass);
 		if(ch->exthost)ch->exthost = (unsigned char*)mystrdup((char *)ch->exthost);
 	}
+	if(preacl){
+		if(ac->dst || ac->ports || ac->users || ac->dstnames || ac->chains|| ac->action>1){
+			preacl = 0;
+			for(acc = srv->preacl; acc; acc=acc->next)if(acc->next == ac) {
+				acc->next = NULL;
+				break;
+			}
+			srv->acl = ac;
+		}
+		else {
+			if(!srv->preacl) srv->preacl = ac;
+		}
+	}
+	
  }
- return ret;
 }
 
 

+ 41 - 11
src/sockmap.c

@@ -8,6 +8,8 @@
 
 #include "proxy.h"
 
+#define MAXFAILATTEMPT 10
+
 #ifdef WITHLOG
 #if WITHLOG > 1
 char logbuf[1024];
@@ -57,6 +59,7 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
  FILTER_ACTION action;
  int res;
  SASIZETYPE sasize;
+ int needaction = 0;
 
 #ifdef WITHSPLICE
  uint64_t inclientpipe = 0, inserverpipe = 0;
@@ -120,17 +123,17 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
  if(action != PASS) RETURN(19);
 
  while(
-	((!CLIENTTERM) && (inserverbuf 
+	((!CLIENTTERM) && fromserver && (inserverbuf 
 #ifdef WITHSPLICE
 		|| inserverpipe 
 #endif
-		|| (!SERVERTERM && fromserver)))
+		|| (!SERVERTERM )))
 	||
-	((!SERVERTERM) && (inclientbuf 
+	((!SERVERTERM) && fromclient && (inclientbuf 
 #ifdef WITHSPLICE
 		|| inclientpipe 
 #endif
-		|| (!CLIENTTERM && fromclient)))
+		|| (!CLIENTTERM )))
  ){
 
 
@@ -155,8 +158,12 @@ sprintf(logbuf, "int FROMCLIENT = %d, TOCLIENTBUF = %d, FROMCLIENTBUF = %d, TOSE
 log(logbuf);
 #endif
 
+	if(needaction > 2 && !sleeptime){
+		if(needaction > (MAXFAILATTEMPT+1)){RETURN (93);}
+		sleeptime = (1<<(needaction-2));
+	}
 	if(sleeptime > 0) {
-		if(sleeptime > (timeo * 1000)){RETURN (92);}
+		if(sleeptime > (timeo * 1000)){RETURN (93);}
 		memset(fds, 0, sizeof(fds));
 		fds[0].fd = param->clisock;
 		fds[1].fd = param->remsock;
@@ -216,6 +223,7 @@ log("done send to server from buf");
 				sl1 = (*param->bandlimfunc)(param, 0, res);
 				if(sl1 > sleeptime) sleeptime = sl1;
 		    	}
+			needaction = 0;
 			continue;
 		}
 	}
@@ -247,6 +255,7 @@ log("done send to client from buf");
 			param->srvoffset += res;
 			if(param->srvoffset == param->srvinbuf)param->srvoffset = param->srvinbuf =0;
 			if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
+			needaction = 0;
 			continue;
 		}
 	}
@@ -270,6 +279,7 @@ log("done send to server from pipe");
 					sl1 = (*param->bandlimfunc)(param, 0, res);
 					if(sl1 > sleeptime) sleeptime = sl1;
 		    		}
+				needaction = 0;
 				continue;
 			}
 			else {
@@ -288,6 +298,7 @@ log("done send to client from pipe");
 				inserverpipe -= res;
 				fromserver -= res;
 				if(fromserver)TOSERVERPIPE = 1;
+				needaction = 0;
 				continue;
 			}
 			else {
@@ -306,6 +317,10 @@ log("read from client to pipe");
 log("read failed");
 #endif
 				FROMCLIENT = TOCLIENTPIPE = 0;
+				if(res == 0) {
+					CLIENTTERM = 1;
+					continue;
+				}
 			}
 			else {
 #ifdef WITHLOG
@@ -313,6 +328,7 @@ log("done read from client to pipe");
 #endif
 				inclientpipe += res;
 				if(inclientpipe >= MAXSPLICE) TOCLIENTPIPE = 0;
+				needaction = 0;
 				continue;
 			}
 		}
@@ -328,6 +344,10 @@ log("splice finished\n");
 #endif
 			if(res <= 0) {
 				FROMSERVER = TOSERVERPIPE = 0;
+				if(res == 0 || !errno) {
+					SERVERTERM = 1;
+					continue;
+				}
 			}
 			else {
 #ifdef WITHLOG
@@ -346,8 +366,9 @@ log("done read from server to pipe\n");
 					fromserver = inserverpipe;
 					FROMSERVER = 0;
 				}
+				needaction = 0;
+				continue;
 			}
-			continue;
 		}
 	}
 	else
@@ -360,8 +381,11 @@ log("read from client to buf");
 			sasize = sizeof(param->sincr);
 			res = so._recvfrom(param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)&param->sincr, &sasize);
 			if(res <= 0) {
-				if(!errno)CLIENTTERM = 1;
 				FROMCLIENT = 0;
+				if(res == 0){
+					CLIENTTERM = 1;
+					continue;
+				}
 			}
 			else {
 #ifdef WITHLOG
@@ -370,6 +394,7 @@ log("done read from client to buf");
 				inclientbuf += res;
 				param->cliinbuf += res;
 				if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
+				needaction = 0;
 				continue;
 			}
 		}
@@ -381,8 +406,11 @@ log("read from server to buf");
 			sasize = sizeof(param->sinsr);
 			res = so._recvfrom(param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)&param->sinsr, &sasize);
 			if(res <= 0) {
-				if(!errno) SERVERTERM = 1;
 				FROMSERVER = 0;
+				if(res == 0) {
+					SERVERTERM = 1;
+					continue;
+				}
 			}
 			else {
 #ifdef WITHLOG
@@ -402,6 +430,7 @@ log("done read from server to buf");
 					fromserver = inserverbuf;
 					FROMSERVER = 0;
 				}
+				needaction = 0;
 				continue;
 			}
 		}
@@ -639,7 +668,7 @@ log("leaving poll");
 #ifdef WITHLOG
 log("poll error");
 #endif
-				if(errno != EAGAIN && errno != EINTR) RETURN(91);
+				if(errno != EINTR) RETURN(91);
 				break;
 			}
 			if(res < 1){
@@ -650,14 +679,15 @@ log("timeout");
 			}
 		}
 	}
+	needaction++;
 
  }
  res = 0;
  if(!fromserver && param->waitserver64) res = 98;
  else if(!fromclient && param->waitclient64) res = 99;
- else if((inclientbuf || inserverbuf)) res = HASERROR?93:94;
+ else if((inclientbuf || inserverbuf)) res = 94;
 #ifdef WITHSPLICE
- else if(inclientpipe || inserverpipe) res = HASERROR?93:94;
+ else if(inclientpipe || inserverpipe) res = 94;
 #endif
  else if(HASERROR) res = 94+HASERROR;
 

+ 4 - 1
src/structures.h

@@ -215,6 +215,7 @@ typedef int (*PLUGINFUNC)(struct pluginlink *pluginlink, int argc, char** argv);
 
 struct auth {
 	struct auth *next;
+	AUTHFUNC preauthorize;
 	AUTHFUNC authenticate;
 	AUTHFUNC authorize;
 	char * desc;
@@ -477,7 +478,7 @@ struct srvparam {
 #endif
 	struct auth *authenticate;
 	struct pollfd * srvfds;
-	struct ace *acl;
+	struct ace *preacl, *acl;
 	struct auth *authfuncs;
 	struct filter *filter;
 	unsigned char * logformat;
@@ -519,6 +520,7 @@ struct clientparam {
 		operation,
 		nfilters, nreqfilters, nhdrfilterscli, nhdrfilterssrv, npredatfilters, ndatfilterscli, ndatfilterssrv,
 		unsafefilter,
+		preauthorized,
 		bandlimver;
 
 	int	res,
@@ -759,6 +761,7 @@ struct pluginlink {
 	int (*ACLMatches)(struct ace* acentry, struct clientparam * param);
 	int (*alwaysauth)(struct clientparam * param);
 	int (*checkACL)(struct clientparam * param);
+	int (*checkpreACL)(struct clientparam * param);
 	void (*nametohash)(const unsigned char * name, unsigned char *hash);
 	unsigned (*hashindex)(const unsigned char* hash);
 	unsigned char* (*en64)(const unsigned char *in, unsigned char *out, int inlen);

+ 1 - 1
src/tcppm.c

@@ -16,7 +16,7 @@
 void * tcppmchild(struct clientparam* param) {
  int res;
 
- if(!param->hostname)parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport));
+ if(!param->hostname && parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) RETURN(100);
  param->operation = CONNECT;
  res = (*param->srv->authfunc)(param);
  if(res) {RETURN(res);}

+ 1 - 1
src/udppm.c

@@ -38,7 +38,7 @@ void * udppmchild(struct clientparam* param) {
  struct pollfd fds[256];
 
 
- if(!param->hostname)parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport));
+ if(!param->hostname && parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) RETURN(100);
  if (SAISNULL(&param->req)) {
 	param->srv->fds.events = POLLIN;
 	RETURN (100);