@@ -189,13 +189,65 @@ def pattern_compile(filename):
189189 with open (filename ) as f :
190190 return re .compile ('(:?' + '' .join ('|' .join (i .strip () for i in f if i .strip () and not i .startswith ('#' )))+ ')$' ).match
191191
192+ class Backward (object ):
193+ MAX_CONN = 1
194+ def __init__ (self , uri ):
195+ self .uri = uri
196+ self .closed = False
197+ self .conn = asyncio .Queue ()
198+ self .open_connection = self .conn .get
199+ self .writer = None
200+ def close (self ):
201+ self .closed = True
202+ try :
203+ self .writer .close ()
204+ except Exception :
205+ pass
206+ async def start_server (self , handler ):
207+ self .handler = handler
208+ for _ in range (self .MAX_CONN ):
209+ asyncio .ensure_future (self .server_run ())
210+ return self
211+ async def server_run (self ):
212+ errwait = 0
213+ while not self .closed :
214+ if self .uri .unix :
215+ wait = asyncio .open_unix_connection (path = self .uri .bind , ssl = self .uri .sslclient , server_hostname = '' if self .uri .sslclient else None )
216+ else :
217+ wait = asyncio .open_connection (host = self .uri .host_name , port = self .uri .port , ssl = self .uri .sslclient , local_addr = (self .uri .lbind , 0 ) if self .uri .lbind else None )
218+ try :
219+ reader , writer = await asyncio .wait_for (wait , timeout = SOCKET_TIMEOUT )
220+ self .writer = writer
221+ data = await reader .read_ ()
222+ if data :
223+ reader ._buffer [0 :0 ] = data
224+ asyncio .ensure_future (self .handler (reader , writer ))
225+ errwait = 0
226+ except Exception as ex :
227+ if not self .closed :
228+ await asyncio .sleep (errwait )
229+ errwait = errwait * 1.3 + 0.1
230+ def client_run (self ):
231+ async def handler (reader , writer ):
232+ while self .conn .qsize () >= self .MAX_CONN :
233+ r , w = await self .conn .get ()
234+ try : w .close ()
235+ except Exception : pass
236+ await self .conn .put ((reader , writer ))
237+ if self .uri .unix :
238+ return asyncio .start_unix_server (handler , path = self .uri .bind , ssl = self .uri .sslserver )
239+ else :
240+ return asyncio .start_server (handler , host = self .uri .host_name , port = self .uri .port , ssl = self .uri .sslserver )
241+
192242class ProxyURI (object ):
193243 def __init__ (self , ** kw ):
194244 self .__dict__ .update (kw )
195245 self .total = 0
196246 self .udpmap = {}
197247 self .handler = None
198248 self .streams = None
249+ if self .backward :
250+ self .backward = Backward (self )
199251 def logtext (self , host , port ):
200252 if self .direct :
201253 return f' -> { host } :{ port } '
@@ -274,6 +326,8 @@ async def open_connection(self, host, port, local_addr, lbind):
274326 raise Exception ('Unknown tunnel endpoint' )
275327 local_addr = local_addr if lbind == 'in' else (lbind , 0 ) if lbind else None
276328 wait = asyncio .open_connection (host = host , port = port , local_addr = local_addr )
329+ elif self .backward :
330+ wait = self .backward .open_connection ()
277331 elif self .unix :
278332 wait = asyncio .open_unix_connection (path = self .bind , ssl = self .sslclient , server_hostname = '' if self .sslclient else None )
279333 else :
@@ -307,7 +361,9 @@ async def prepare_ciphers_and_headers(self, reader_remote, writer_remote, host,
307361 return reader_remote , writer_remote
308362 def start_server (self , args ):
309363 handler = functools .partial (reuse_stream_handler if self .reuse else stream_handler , ** vars (self ), ** args )
310- if self .unix :
364+ if self .backward :
365+ return self .backward .start_server (handler )
366+ elif self .unix :
311367 return asyncio .start_unix_server (handler , path = self .bind , ssl = self .sslserver )
312368 else :
313369 return asyncio .start_server (handler , host = self .host_name , port = self .port , ssl = self .sslserver , reuse_port = args .get ('ruport' ))
@@ -384,8 +440,8 @@ def compile(cls, uri, relay=None):
384440 match = match , bind = loc or urlpath , host_name = host_name , port = port , \
385441 unix = not loc , lbind = lbind , sslclient = sslclient , sslserver = sslserver , \
386442 alive = True , direct = 'direct' in protonames , tunnel = 'tunnel' in protonames , \
387- reuse = 'pack' in protonames or relay and relay .reuse , relay = relay )
388- ProxyURI .DIRECT = ProxyURI (direct = True , tunnel = False , reuse = False , relay = None , alive = True , match = None , cipher = None )
443+ reuse = 'pack' in protonames or relay and relay .reuse , backward = 'in' in rawprotos , relay = relay )
444+ ProxyURI .DIRECT = ProxyURI (direct = True , tunnel = False , reuse = False , relay = None , alive = True , match = None , cipher = None , backward = None )
389445
390446async def test_url (url , rserver ):
391447 url = urllib .parse .urlparse (url )
@@ -480,6 +536,14 @@ def main():
480536 servers .append (server )
481537 except Exception as ex :
482538 print ('Start server failed.\n \t ==>' , ex )
539+ for option in args .rserver :
540+ if option .backward :
541+ print ('Serving on' , option .bind , 'backward by' , "," .join (i .name for i in option .protos ) + ('(SSL)' if option .sslclient else '' ), '({}{})' .format (option .cipher .name , ' ' + ',' .join (i .name () for i in option .cipher .plugins ) if option .cipher and option .cipher .plugins else '' ) if option .cipher else '' )
542+ try :
543+ server = loop .run_until_complete (option .backward .client_run ())
544+ servers .append (server )
545+ except Exception as ex :
546+ print ('Start server failed.\n \t ==>' , ex )
483547 if servers :
484548 if args .sys :
485549 from . import sysproxy
0 commit comments