Authorizer und Passive Datenverbindung implementiert
This commit is contained in:
parent
54e1e9b5c8
commit
c1a08ba821
1 changed files with 164 additions and 38 deletions
202
fakeftp.py
202
fakeftp.py
|
@ -1,6 +1,56 @@
|
||||||
import SocketServer
|
import SocketServer
|
||||||
|
import threading
|
||||||
|
import socket
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
class DataConnection:
|
||||||
|
def run(self, dchandler):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PassiveDataConnection(DataConnection):
|
||||||
|
def __init__(self, port):
|
||||||
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.socket.bind(("",port))
|
||||||
|
threading.Thread(target=self.waitForConnection).start()
|
||||||
|
|
||||||
|
def waitForConnection(self):
|
||||||
|
self.socket.listen(1)
|
||||||
|
self.connection, _ = self.socket.accept()
|
||||||
|
|
||||||
|
def run(self, dchandler):
|
||||||
|
threading.Thread(target=self.runHandler, args=(dchandler,) ).start()
|
||||||
|
|
||||||
|
def runHandler(self, dchandler):
|
||||||
|
dchandler.handle(self.connection)
|
||||||
|
self.connection.close()
|
||||||
|
|
||||||
|
class ActiveDataConnection(DataConnection):
|
||||||
|
def __init__(self, host, port):
|
||||||
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.socket.connect( (host,port) )
|
||||||
|
|
||||||
|
def run(self, dchandler):
|
||||||
|
threading.Thread(target=self.runHandler, args=(dchandler,)).start()
|
||||||
|
|
||||||
|
def runHandler(self, dchandler):
|
||||||
|
dchandler.handle(self.socket)
|
||||||
|
self.socket.close()
|
||||||
|
|
||||||
|
class FailAuthorizer:
|
||||||
|
'''Default authorizer. Denys all logins'''
|
||||||
|
def authorize(self, username, password, handler):
|
||||||
|
return False
|
||||||
|
|
||||||
|
class AnonymousAuthorizer:
|
||||||
|
def authorize(self, username, password, handler):
|
||||||
|
if username in ["ftp","anonymous"]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
class FTPMessage:
|
class FTPMessage:
|
||||||
|
'''Parses and creates FTP Messages'''
|
||||||
def __init__(self,cmd,parameter):
|
def __init__(self,cmd,parameter):
|
||||||
self.cmd = cmd
|
self.cmd = cmd
|
||||||
self.parameter = parameter
|
self.parameter = parameter
|
||||||
|
@ -22,50 +72,102 @@ class FTPMessage:
|
||||||
param = line[pos+1:]
|
param = line[pos+1:]
|
||||||
return FTPMessage(cmd.upper(),param)
|
return FTPMessage(cmd.upper(),param)
|
||||||
|
|
||||||
class GeneralState:
|
class QuitMessage(FTPMessage):
|
||||||
@staticmethod
|
'''Message sent to client when client wants to disconnect'''
|
||||||
def handle(self, message):
|
def __init__(self):
|
||||||
|
FTPMessage.__init__(self,"221","Goodbye.")
|
||||||
|
|
||||||
|
class InvalidCommandMessage(FTPMessage):
|
||||||
|
'''Message sent to client when server received message it didn't understand'''
|
||||||
|
def __init__(self,cmd):
|
||||||
|
FTPMessage.__init__(self,"500","%s not understood" % cmd)
|
||||||
|
|
||||||
|
class PasswordRequiredMessage(FTPMessage):
|
||||||
|
'''Message sent to client when it specified a username'''
|
||||||
|
def __init__(self,user):
|
||||||
|
FTPMessage.__init__(self,"331","Password required for %s" % user)
|
||||||
|
|
||||||
|
class AuthorizationSuccessfulMessage(FTPMessage):
|
||||||
|
'''Message sent to client when authorization was successful'''
|
||||||
|
def __init__(self):
|
||||||
|
FTPMessage.__init__(self,"230","Welcome user.")
|
||||||
|
|
||||||
|
class AuthorizationFailedMessage(FTPMessage):
|
||||||
|
'''Message sent to client when authorization failed'''
|
||||||
|
def __init__(self):
|
||||||
|
FTPMessage.__init__(self,"530","Login incorrect.")
|
||||||
|
|
||||||
|
class WelcomeMessage(FTPMessage):
|
||||||
|
'''Message sent to client after client has connected'''
|
||||||
|
def __init__(self):
|
||||||
|
FTPMessage.__init__(self,"220","FTP Server ready")
|
||||||
|
|
||||||
|
class EnteringPassiveModeMessage(FTPMessage):
|
||||||
|
def __init__(self,addrtuple):
|
||||||
|
FTPMessage.__init__(self,"227","Entering Passive Mode %s." % addrtuple)
|
||||||
|
|
||||||
|
# Data Connection Handler
|
||||||
|
class HeloHandler:
|
||||||
|
def handle(self, socket):
|
||||||
|
socket.send("Hello World")
|
||||||
|
|
||||||
|
# State classes
|
||||||
|
class State:
|
||||||
|
def process(self, handler, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MainState(State):
|
||||||
|
def process(self, handler, message):
|
||||||
if message.cmd == "QUIT":
|
if message.cmd == "QUIT":
|
||||||
self.debug("Client wants to quit")
|
handler.send( QuitMessage() )
|
||||||
self.send(FTPMessage("221","Goodbye."))
|
handler.running = False
|
||||||
self.handler.running = False
|
|
||||||
else:
|
else:
|
||||||
self.debug("Unknown command %s" % message.cmd)
|
handler.send( InvalidCommandMessage(message.cmd) )
|
||||||
self.send(FTPMessage("500", "%s not understood" % message.cmd ))
|
|
||||||
|
|
||||||
class UserState:
|
class NonAuthorizedState(MainState):
|
||||||
@staticmethod
|
def process(self, handler, message):
|
||||||
def handle(self, message):
|
|
||||||
if message.cmd == "USER":
|
if message.cmd == "USER":
|
||||||
self.debug("Initiating login for user %s" % message.parameter)
|
handler.user = message.parameter
|
||||||
self.send(FTPMessage("331","Password required for %s" % message.parameter))
|
handler.state = AuthorizingState()
|
||||||
self.state = PassState
|
handler.send( PasswordRequiredMessage(handler.user) )
|
||||||
else:
|
else:
|
||||||
GeneralState.handle(self, message)
|
MainState.process(self, handler, message)
|
||||||
|
|
||||||
class PassState:
|
class AuthorizingState(MainState):
|
||||||
@staticmethod
|
def process(self, handler, message):
|
||||||
def handle(self, message):
|
|
||||||
if message.cmd == "PASS":
|
if message.cmd == "PASS":
|
||||||
self.debug("Denying access with password %s" % message.parameter)
|
password = message.parameter
|
||||||
self.send(FTPMessage("530","Login incorrect."))
|
if handler.authorizer.authorize(handler.user, password, handler):
|
||||||
self.state = UserState
|
handler.debug("User login %s successful" % handler.user)
|
||||||
|
handler.state = AuthorizedState()
|
||||||
|
handler.send( AuthorizationSuccessfulMessage() )
|
||||||
else:
|
else:
|
||||||
GeneralState.handle(self, message)
|
handler.debug("User login %s failed" % handler.user)
|
||||||
|
handler.state = NonAuthorizedState()
|
||||||
|
handler.send( AuthorizationFailedMessage() )
|
||||||
|
else:
|
||||||
|
MainState.process(self, handler, message)
|
||||||
|
|
||||||
class FTPMessageHandler:
|
class AuthorizedState(MainState):
|
||||||
def __init__(self, handler):
|
def addrtuple(self, ip, port):
|
||||||
self.state = UserState
|
b = ip.split(".")
|
||||||
self.handler = handler
|
b.append( str( (port >> 8) & 0xFF ) )
|
||||||
|
b.append( str( port & 0xFF ) )
|
||||||
|
return "(" + ",".join(b)+ ")"
|
||||||
|
|
||||||
def send(self,data):
|
def process(self, handler, message):
|
||||||
return self.handler.request.send( str(data) )
|
if message.cmd == "PASV":
|
||||||
|
port = handler.createPassiveDataConnection()
|
||||||
def debug(self,text):
|
handler.debug("Created passive data connection")
|
||||||
self.handler.debug(text)
|
handler.send( EnteringPassiveModeMessage( self.addrtuple("127.0.0.1",port) ) )
|
||||||
|
elif message.cmd == "HELO":
|
||||||
def handle(self, message):
|
handler.debug("Running Helo on data connection")
|
||||||
self.state.handle(self, message)
|
if handler.runDataConnection(HeloHandler()):
|
||||||
|
handler.debug("successful")
|
||||||
|
else:
|
||||||
|
handler.debug("failed")
|
||||||
|
else:
|
||||||
|
MainState.process(self, handler, message)
|
||||||
|
|
||||||
class LineReader:
|
class LineReader:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -88,12 +190,33 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
def debug(self, text):
|
def debug(self, text):
|
||||||
print ("[%s] " % self.client_address[0]) + text
|
print ("[%s] " % self.client_address[0]) + text
|
||||||
|
|
||||||
|
def send(self, message):
|
||||||
|
self.request.send( str(message) )
|
||||||
|
|
||||||
|
def createPassiveDataConnection(self):
|
||||||
|
port = randint(60000,63000)
|
||||||
|
self.connection = PassiveDataConnection(port)
|
||||||
|
return port
|
||||||
|
|
||||||
|
def createActiveDataConnection(self,port):
|
||||||
|
self.connection = ActiveDataConnection(self.client_address[0],port)
|
||||||
|
|
||||||
|
def runDataConnection(self, dchandler):
|
||||||
|
if self.connection is None:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.connection.run(dchandler)
|
||||||
|
self.connection = None
|
||||||
|
return True
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
self.messagehandler = FTPMessageHandler(self)
|
self.connection = None
|
||||||
|
|
||||||
|
self.state = NonAuthorizedState()
|
||||||
|
|
||||||
self.debug("Client connected");
|
self.debug("Client connected");
|
||||||
|
|
||||||
self.request.send(FTPMessage("220","FTP Server ready").generate())
|
self.send( WelcomeMessage() )
|
||||||
|
|
||||||
linereader = LineReader()
|
linereader = LineReader()
|
||||||
|
|
||||||
|
@ -108,10 +231,13 @@ class FTPHandler(SocketServer.BaseRequestHandler):
|
||||||
|
|
||||||
for line in linereader.get_lines():
|
for line in linereader.get_lines():
|
||||||
message = FTPMessage.parse(line)
|
message = FTPMessage.parse(line)
|
||||||
self.messagehandler.handle(message)
|
self.state.process(self,message)
|
||||||
|
|
||||||
self.debug("Client disconnected")
|
self.debug("Client disconnected")
|
||||||
|
|
||||||
server = SocketServer.ThreadingTCPServer(("",1234),FTPHandler)
|
handler = FTPHandler
|
||||||
|
handler.authorizer = AnonymousAuthorizer()
|
||||||
|
|
||||||
|
server = SocketServer.ThreadingTCPServer(("",1234),handler)
|
||||||
|
|
||||||
server.serve_forever()
|
server.serve_forever()
|
Loading…
Reference in a new issue