# -*- Mode: Python; tab-width: 4 -*- # A 'forwarding' FTP proxy. In combination with PASV mode, allows you # pipe the control connection through a separate host/process. # +--------+ high bandwidth +----------------------+ # | client |<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<| connected FTP server | # +--------+ +----------------------+ # \ / # \ / # \ / # \ / # \ / # \ / # \ / # low bandwidth ->\ /<- low bandwidth # \ / # \ / # \ / # \ / # +--------+ # | medusa | # +--------+ import asynchat import asyncore import socket import sys import time # this is the client that connects to the 'real' ftp server. class forwarding_proxy (asynchat.async_chat): def __init__ (self, channel): asynchat.async_chat.__init__ (self) self.channel = channel self.set_terminator ('\r\n') self.create_socket (socket.AF_INET, socket.SOCK_STREAM) self.connect (channel.server.proxy_addr) self.data = '' def handle_connect (self): print 'connected to proxy server' def collect_incoming_data (self, data): self.data = self.data + data def found_terminator (self): line = self.data print '<==',line self.data = '' self.channel.push (line+'\r\n') def handle_close (self): print 'proxy closed' self.channel.close() self.close() # this is the server channel that redirects through the proxy class forwarding_ftp_channel (asynchat.async_chat): def __init__ (self, server, conn, addr): asynchat.async_chat.__init__ (self, conn) self.server = server self.set_terminator ('\r\n') self.addr = addr self.proxy = forwarding_proxy (self) self.data = '' def collect_incoming_data (self, data): self.data = self.data + data def found_terminator (self): line = self.data print '==>',line self.data = '' self.proxy.push (line+'\r\n') def handle_close (self): print 'channel closed' self.proxy.close() self.close() class forwarding_ftp_server (asyncore.dispatcher): channel_class = forwarding_ftp_channel def __init__ (self, local_addr, proxy_addr): asyncore.dispatcher.__init__ (self) self.create_socket (socket.AF_INET, socket.SOCK_STREAM) self.bind (local_addr) self.listen (5) print 'Forwarding FTP server started at %s\n\tLocal Address:%s\n\tRemote Address:%s\n' % ( time.ctime(time.time()), local_addr, proxy_addr ) self.proxy_addr = proxy_addr def handle_accept (self): conn, addr = self.accept() print 'incoming connection from %s' % repr(addr) sys.stdout.flush() self.channel_class (self, conn, addr) if __name__ == '__main__': import sys import string if len(sys.argv) == 1: print 'Usage: %s <local_ip> <local_port> <remote_host>' % sys.argv[0] else: fs = forwarding_ftp_server ( (sys.argv[1], string.atoi (sys.argv[2])), (sys.argv[3], 21) ) asyncore.loop()