175 lines
4.9 KiB
Python
175 lines
4.9 KiB
Python
import socket, threading, time
|
|
import StringIO
|
|
|
|
__author__ = 'hoffer'
|
|
|
|
|
|
class FTPServer(threading.Thread):
|
|
def __init__(self, local_ip, local_port, files):
|
|
self.files=files
|
|
self.cwd='/'
|
|
self.mode='I'
|
|
self.rest=False
|
|
self.pasv_mode=False
|
|
self.local_ip = local_ip
|
|
self.local_port = local_port
|
|
threading.Thread.__init__(self)
|
|
|
|
def run(self):
|
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.sock.bind((self.local_ip,self.local_port))
|
|
self.sock.listen(1)
|
|
|
|
self.conn, self.addr = self.sock.accept()
|
|
|
|
self.conn.send('220 Welcome!\r\n')
|
|
while True:
|
|
if 0 == len(self.files):
|
|
break
|
|
cmd=self.conn.recv(256)
|
|
if not cmd: break
|
|
else:
|
|
try:
|
|
func=getattr(self,cmd[:4].strip().upper())
|
|
func(cmd)
|
|
except Exception as e:
|
|
self.conn.send('500 Sorry.\r\n')
|
|
break
|
|
|
|
self.conn.close()
|
|
self.sock.close()
|
|
|
|
def SYST(self,cmd):
|
|
self.conn.send('215 UNIX Type: L8\r\n')
|
|
def OPTS(self,cmd):
|
|
if cmd[5:-2].upper()=='UTF8 ON':
|
|
self.conn.send('200 OK.\r\n')
|
|
else:
|
|
self.conn.send('451 Sorry.\r\n')
|
|
def USER(self,cmd):
|
|
self.conn.send('331 OK.\r\n')
|
|
|
|
def PASS(self,cmd):
|
|
self.conn.send('230 OK.\r\n')
|
|
|
|
def QUIT(self,cmd):
|
|
self.conn.send('221 Goodbye.\r\n')
|
|
|
|
def NOOP(self,cmd):
|
|
self.conn.send('200 OK.\r\n')
|
|
|
|
def TYPE(self,cmd):
|
|
self.mode=cmd[5]
|
|
self.conn.send('200 Binary mode.\r\n')
|
|
|
|
def CDUP(self,cmd):
|
|
self.conn.send('200 OK.\r\n')
|
|
|
|
def PWD(self,cmd):
|
|
self.conn.send('257 \"%s\"\r\n' % self.cwd)
|
|
|
|
def CWD(self,cmd):
|
|
self.conn.send('250 OK.\r\n')
|
|
|
|
def PORT(self,cmd):
|
|
if self.pasv_mode:
|
|
self.servsock.close()
|
|
self.pasv_mode = False
|
|
l = cmd[5:].split(',')
|
|
self.dataAddr='.'.join(l[:4])
|
|
self.dataPort=(int(l[4])<<8)+int(l[5])
|
|
self.conn.send('200 Get port.\r\n')
|
|
|
|
def PASV(self,cmd):
|
|
self.pasv_mode = True
|
|
self.servsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
self.servsock.bind((self.local_ip,0))
|
|
self.servsock.listen(1)
|
|
ip, port = self.servsock.getsockname()
|
|
self.conn.send('227 Entering Passive Mode (%s,%u,%u).\r\n' %
|
|
(','.join(ip.split('.')), port>>8&0xFF, port&0xFF))
|
|
|
|
def start_datasock(self):
|
|
if self.pasv_mode:
|
|
self.datasock, addr = self.servsock.accept()
|
|
else:
|
|
self.datasock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
|
self.datasock.connect((self.dataAddr,self.dataPort))
|
|
|
|
def stop_datasock(self):
|
|
self.datasock.close()
|
|
if self.pasv_mode:
|
|
self.servsock.close()
|
|
|
|
def LIST(self,cmd):
|
|
self.conn.send('150 Here comes the directory listing.\r\n')
|
|
self.start_datasock()
|
|
for fn in self.files.keys():
|
|
k=self.toListItem(fn)
|
|
self.datasock.send(k+'\r\n')
|
|
self.stop_datasock()
|
|
self.conn.send('226 Directory send OK.\r\n')
|
|
|
|
def toListItem(self,fn):
|
|
fullmode='rwxrwxrwx'
|
|
mode = ''
|
|
d = '-'
|
|
ftime=time.strftime(' %b %d %H:%M ', time.gmtime())
|
|
return d+fullmode+' 1 user group '+str(self.files[fn].tell())+ftime+fn
|
|
|
|
def MKD(self,cmd):
|
|
self.conn.send('257 Directory created.\r\n')
|
|
|
|
def RMD(self,cmd):
|
|
self.conn.send('450 Not allowed.\r\n')
|
|
|
|
def DELE(self,cmd):
|
|
self.conn.send('450 Not allowed.\r\n')
|
|
|
|
def SIZE(self,cmd):
|
|
self.conn.send('450 Not allowed.\r\n')
|
|
|
|
def RNFR(self,cmd):
|
|
self.conn.send('350 Ready.\r\n')
|
|
|
|
def RNTO(self,cmd):
|
|
self.conn.send('250 File renamed.\r\n')
|
|
|
|
def REST(self,cmd):
|
|
self.pos=int(cmd[5:-2])
|
|
self.rest=True
|
|
self.conn.send('250 File position reseted.\r\n')
|
|
|
|
def RETR(self,cmd):
|
|
fn = cmd[5:-2]
|
|
if self.mode=='I':
|
|
fi=self.files[fn]
|
|
else:
|
|
fi=self.files[fn]
|
|
self.conn.send('150 Opening data connection.\r\n')
|
|
if self.rest:
|
|
fi.seek(self.pos)
|
|
self.rest=False
|
|
data= fi.read(1024)
|
|
self.start_datasock()
|
|
while data:
|
|
self.datasock.send(data)
|
|
data=fi.read(1024)
|
|
fi.close()
|
|
del self.files[fn]
|
|
self.stop_datasock()
|
|
self.conn.send('226 Transfer complete.\r\n')
|
|
|
|
def STOR(self,cmd):
|
|
fn = cmd[5:-2]
|
|
fo = StringIO.StringIO()
|
|
self.conn.send('150 Opening data connection.\r\n')
|
|
self.start_datasock()
|
|
while True:
|
|
data=self.datasock.recv(1024)
|
|
if not data: break
|
|
fo.write(data)
|
|
fo.seek(0)
|
|
self.stop_datasock()
|
|
self.conn.send('226 Transfer complete.\r\n')
|